﻿# 開發SQL相關應用程式時要注意登入帳號的預設結構描述

上週我經手一個案子，客戶原本將網站架設在自己公司，且運作正常好一段時間了，但最近將網站與資料庫搬遷到[戰國策](http://www.hotels.com.tw/)之後卻發現有部分程式無法執行了。因為這已經是結案的案子，所以客戶原本想自行解決這個問題，但在嘗試了一整天之後才請我幫他找問題。

首先，這個網站在我的電腦與公司的測試主機都可以正常執行，但當我將資料庫連線切換到[戰國策](http://www.hotels.com.tw/)提供的 SQL Server 主機之後就會出現異常，錯誤訊息如下：

```
System.Data.ConstraintException:
```

```
  無法啟用條件約束。一或多個資料列的值違反非 Null、唯一或外部索引鍵條件約束。
```

又是這種「萬用錯誤訊息」，這種 Exception 錯誤訊息應該是 ASP.NET 初學者最怕的吧，完全不知道該從何下手解決問題。

因為是 Typed DataSet 在取得資料時出現的問題，且程式「曾經」跑過一段時間都沒問題，是在切換到不同資料庫時才發生問題的，所以我直覺的研判程式部分應該沒問題，所以我就打算直接從資料庫著手調查原因。

經過十幾分鐘的奮戰，我發現原來是戰國策所開給我們客戶的 **SQL Server 登入帳號**所對應到**資料庫中的使用者**，被指派了一個**跟帳號同名**的**預設結構描述**(Default Schema)，但我查了一下我們寫的程式，在 Typed DataSet 中的 TableAdapter 中的查詢設定，並沒有特別在 T-SQL 中指令結構描述(Schema)，所以我們預期所有表格都應該使用 dbo 這個預設的結構描述才對。

例如以下語法：

```
SELECT * FROM members WHERE enabled=1
```

在 SQL Server 中預設會轉成這樣子來執行：

```
SELECT * FROM dbo.members WHERE enabled=1
```

不過客戶從轉移主機之後，該資料庫裡的使用者卻被指定了與帳號同名的預設結構描述（例如：user1），而這樣的設定值導致我們的程式中的 T-SQL 被轉成以下：

```
SELECT * FROM user1.members WHERE enabled=1
```

所以才會找不到表格，或找到不同結構描述但表格名稱相同的表格而出現錯誤。

所以這告訴我兩個實務經驗：

1.  在開發與 SQL Server 相關的應用程式時，所下的任何 T-SQL 語法都應該加上適當的「結構描述」(Schema)，以免相同的問題再度發生。
2.  資料庫在轉移或重建的時候，要特別注意資料庫使用者的相關設定是否跟原來的一樣，尤其是「預設結構描述」的部分最有可能影響應用程式的運作！

修改預設結構描述的方式如下：

![修改預設結構描述的方式](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/b744fb7de1060c4ddc2b-image_3.png) 

查看目前使用者的「預設結構描述」設定：

![資料庫使用者 - test](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/4fba6d17e22051d64e5d-image_6.png)

最後將預設結構描述修改為 dbo 即可。
