none
若資料庫中有些欄位是預設值,在 Entity Framework 中應該怎麼處理? RRS feed

  • 問題

  • 請問有人知道若資料庫中有些欄位是預設值,在 Entity Framework 中應該怎麼處理嗎?

    我的表格中有兩個欄位在 Insert 的時候是不需要設定值的,包括:

    1.  ID  uniqueidentifier        newid()
    2.  CreateTime  datetime    getdate()

    不過當我在新增資料時,都一定要指定才能新增成功。

    若我只指定 ID 的話,錯誤訊息卻出現:

        The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.
        The statement has been terminated.

    很詭異的錯誤訊息,雖然我用的是 SQL Server 2008 但我欄位明明就宣告 datetime 而已,哪來的 datetime2?感覺應該是 EF 的 Bug。
    2009年2月8日 上午 11:05

解答

  • 在回答問題之前先說明一件事,目前dotnet內建的EDM Tools功能實在非常不完整,很多東西並分EF未Support,而是Tool未支援,所以很多情況你必須手動修改EDM File.也就是你要懂CSDL,SSDL,MSL這三個檔案的規則.
    目前市面中文版上除了黃大哥的極意之道這本有提起入門的CSDL,SSDL,MSL說明外其他幾乎沒中文資料可循,最完整的資訊還是MSDN.
    http://msdn.microsoft.com/en-us/library/bb399572.aspx
    也因此我現在幾乎沒在用那個內建Tool,因為實在太難用.所以底下的回覆我不確定Tool是否能夠支援,如不能你必須直接編輯EDM File.
    但注意一點,編輯後的EDM檔案可能就會失去EDM Tool功能.因為Tool可能無法認得某些標籤導致失效


    =========================================================================================================
    你的問題分為兩個

    1.newid的問題
    你必須直接編輯在EDM file中定義StoreGeneratedPattern="Computed",請設定SSDL檔非CSDL
    譬如
    <Property Name="rowguid" Type="uniqueidentifier" Nullable="false" StoreGeneratedPattern="Computed"/> 


    2.由於EF在設計上並未限定Database為哪種.
    故無法直接使用特定SQL的Function,因這樣做會導致不同DB支援問題.
    但由於EF的SQL Provider本身負責轉譯動作,所以某些特定指令經過Provider是可以直接轉譯為特定SQL語法,但這必須是Provider提供.



    如果你要使用自訂SQL Function則必須額外設定
    如使用EDM tool,則在設定新增EDM檔案時勾選你要的UserFunction.然後工具會產生相對應的設定.
    如不要使用EDM tool,則必須修改SSDL檔來定義,方式與下面內建雷同.

    如果你要使用內建的SQL Function由於EDM tool並未支援所以你必須自行手動於SSDL加上
    譬如底下的內建SUBSTRING方法 參考 http://msdn.microsoft.com/en-us/library/bb738614.aspx
    <?xml version="1.0" encoding="utf-8"?>  
    <Schema Namespace="Northwind" Alias="Self"   
    xmlns:edm="http://schemas.microsoft.com/ado/2006/04/edm/ssdl" 
       xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl">  
     
       <! Other declarations.--> 
      <Function Name="SUBSTRING" ReturnType="varchar" BuiltIn="true">  
        <Documentation>   
           <Summary>Function accepts a source string, the starting position  
             and the length of the sub-string to be extracted</Summary>   
           <LongDescription>Long Description if needed. </LongDescription>   
        </Documentation> 
     
        <Parameter Name="str" Mode="In" Type="varchar" /> 
        <Parameter Name="start" Mode="In" Type="int">  
          <Documentation>   
            <Summary>The starting position of the substring</Summary>   
            <LongDescription>Long Description.</LongDescription>   
          </Documentation> 
        </Parameter> 
     
        <Parameter Name="length" Mode="In" Type="int" /> 
      </Function> 
     
    </Schema> 
     

    程式中就可以用LINQ方式使用.


    • 已標示為解答 Will_Huang 2009年3月2日 上午 02:12
    2009年2月9日 上午 06:56

所有回覆

  • 那個DateTime2欄位只是LINQ轉譯成SQL語法後的一個別名.
    你的問題可以在用下列Function列出EF產生的SQL語法來確認問題


     

     
    var q = from .....
    Console.Write(LINQExtensionMethods.ToTraceString(q));


    // LINQExtensionMethods  class
        public static class LINQExtensionMethods  
        {  
            public static string ToTraceString(this IQueryable query)  
            {  
                System.Reflection.MethodInfo toTraceStringMethod = query.GetType().GetMethod("ToTraceString");  
     
                if (toTraceStringMethod != null)  
                    return toTraceStringMethod.Invoke(query, null).ToString();  
                else  
                    return "";  
            }  
        }  
     
    2009年2月9日 上午 12:32
  •  但我還沒用到 LINQ 耶!我的程式如下:

    Category c = new Category();  
    c.Title = "TEST Title";  
    db.AddToCategory(c);  
    db.SaveChanges(); 

    請問這樣要如何追查?好像沒有地方可以調整說!應該是 Provider 那邊的問題。

    我用 SQL Server Profiler 查到的結果是真的在執行 INSERT INTO 時被轉譯成 datetime2 了,我只要將我的表格日期欄位改成 datetime2(7) 格式即可,執行的語法如下:

    exec sp_executesql N'insert [dbo].[Category]([ID], [Title], [CreateTime])
    values (@0, @1, @2)',  
    N'@0 uniqueidentifier,@1 nvarchar(3),@2 datetime2(7)',  
    @0='00000000-0000-0000-0000-000000000000',  
    @1=N'123',  
    @2='0001-01-01 00:00:00' 
     

    不過這不是我的主要問題,我的主要問題是若資料庫中有些欄位是預設值,在 Entity Framework 中應該怎麼處理?

     

    2009年2月9日 上午 01:50
  • 如果你用的是內建的EDM編輯器
    請點選你要設定的欄位然後在右邊屬性視窗中有個 "預設值" 設定你要預設的資料即可.

    或是編輯CSDL(EDM)中相關屬性增加DefaultValue=...方式,與上述兩者是相同的.
    2009年2月9日 上午 02:05
  • 這裡只能指定固定的預設值吧?像我的值是 newid() 與 getdate() 函數,且還是在 SQL Server 中的函數,好像不能在 Entity Framework 中使用的樣子?
    2009年2月9日 上午 04:31
  • 在回答問題之前先說明一件事,目前dotnet內建的EDM Tools功能實在非常不完整,很多東西並分EF未Support,而是Tool未支援,所以很多情況你必須手動修改EDM File.也就是你要懂CSDL,SSDL,MSL這三個檔案的規則.
    目前市面中文版上除了黃大哥的極意之道這本有提起入門的CSDL,SSDL,MSL說明外其他幾乎沒中文資料可循,最完整的資訊還是MSDN.
    http://msdn.microsoft.com/en-us/library/bb399572.aspx
    也因此我現在幾乎沒在用那個內建Tool,因為實在太難用.所以底下的回覆我不確定Tool是否能夠支援,如不能你必須直接編輯EDM File.
    但注意一點,編輯後的EDM檔案可能就會失去EDM Tool功能.因為Tool可能無法認得某些標籤導致失效


    =========================================================================================================
    你的問題分為兩個

    1.newid的問題
    你必須直接編輯在EDM file中定義StoreGeneratedPattern="Computed",請設定SSDL檔非CSDL
    譬如
    <Property Name="rowguid" Type="uniqueidentifier" Nullable="false" StoreGeneratedPattern="Computed"/> 


    2.由於EF在設計上並未限定Database為哪種.
    故無法直接使用特定SQL的Function,因這樣做會導致不同DB支援問題.
    但由於EF的SQL Provider本身負責轉譯動作,所以某些特定指令經過Provider是可以直接轉譯為特定SQL語法,但這必須是Provider提供.



    如果你要使用自訂SQL Function則必須額外設定
    如使用EDM tool,則在設定新增EDM檔案時勾選你要的UserFunction.然後工具會產生相對應的設定.
    如不要使用EDM tool,則必須修改SSDL檔來定義,方式與下面內建雷同.

    如果你要使用內建的SQL Function由於EDM tool並未支援所以你必須自行手動於SSDL加上
    譬如底下的內建SUBSTRING方法 參考 http://msdn.microsoft.com/en-us/library/bb738614.aspx
    <?xml version="1.0" encoding="utf-8"?>  
    <Schema Namespace="Northwind" Alias="Self"   
    xmlns:edm="http://schemas.microsoft.com/ado/2006/04/edm/ssdl" 
       xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl">  
     
       <! Other declarations.--> 
      <Function Name="SUBSTRING" ReturnType="varchar" BuiltIn="true">  
        <Documentation>   
           <Summary>Function accepts a source string, the starting position  
             and the length of the sub-string to be extracted</Summary>   
           <LongDescription>Long Description if needed. </LongDescription>   
        </Documentation> 
     
        <Parameter Name="str" Mode="In" Type="varchar" /> 
        <Parameter Name="start" Mode="In" Type="int">  
          <Documentation>   
            <Summary>The starting position of the substring</Summary>   
            <LongDescription>Long Description.</LongDescription>   
          </Documentation> 
        </Parameter> 
     
        <Parameter Name="length" Mode="In" Type="int" /> 
      </Function> 
     
    </Schema> 
     

    程式中就可以用LINQ方式使用.


    • 已標示為解答 Will_Huang 2009年3月2日 上午 02:12
    2009年2月9日 上午 06:56
  • programlin,

    謝謝,你的回覆對我很有幫助,至少我知道如何讓 Entity Framework 幫我設定欄位的預設值,而且修改 SSDL 的內容並不會影響 ADO.NET Entity Data Model Designer 的運作。

    另外,我也發現只要是 Primary Key 是用 uniqueidentifier 欄位就無法在 'StoreGeneratedPattern' 設定為 'Computed' 或 'Identity'

    如果設定為 'Computed' 會出現以下錯誤:

    Modifications to tables where a primary key column has property 'StoreGeneratedPattern' set to 'Computed' are not supported. Use 'Identity' pattern instead. Key column: 'ID'. Table: 'NewsModel.Store.Category'.  

    如果設定為 'Identity' 會出現以下錯誤:

    Server-generated keys are only supported for identity columns. Key column 'ID' has type 'SqlServer.uniqueidentifier', which is not a valid type for an identity column.

    這應該無解了吧.
    2009年3月2日 上午 02:12
  • 因為在SQL設定uniqueidentifier型態欄位,即使是用ADO或SQL語法新增資料,還是必須自行指定這個欄位的值,因為uniqueidentifier不像識別欄位會自動新增累加然後填入SQL.

    知道這個因素後解決此問題的方式很簡單
    在SQL管理介面中對uniqueidentifier欄位設定"預設值"為NEWID()這個函式即可,這樣SQL就會在產生資料時自動產生GUID.

    而在EF中再修改SSDL的'StoreGeneratedPattern'為'Identity'即可.

    'StoreGeneratedPattern'中的'Identity'表示此欄位再新增時由SQL產生資料
    'Computed'代表此欄位再新增與更新時由SQL產生資料

    所以'Identity'的意思與SQL中的定義是不同的
    2009年3月4日 上午 02:36
  • 我剛剛發現你的錯誤訊息,忘了說明一件事
    對於SQL uniqueidentifier支援有一些限制,不支援"SQL 2000"

    開發團隊有回應如下.
    http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/96b53cf0-2a0a-459d-a26e-52486dc4fb1f/

    依最後面回應看來,因架構問題,看來正式版應該也還是未支援.
    2009年3月4日 上午 02:50
  • update 一下,若搭配 VS2010 + EF2 + POCO

    則完全不需要自行修改 EDMX 的檔案,只要同步後 EDMX 就會自動幫你選好。不用擔心會被蓋掉的問題了

     

     

     

    2010年12月6日 上午 03:11