2012-08-16 34 views
2

我們模型中的大多數表都有一個名爲「intConcurrencyID」的字段,我們打算使用該字段來進行併發檢查。我相信在數據庫優先環境中啓用此字段進行併發檢查的唯一方法是將併發模式設置爲固定。但是,如果我們每個EDMX有大量的表格,我們將很難爲每個實體手動配置每種類型,更不用說某些實體被忽略的可能性。將自動化併發模式設置爲在EDMX中修復

你對我如何自動化這個過程有什麼想法嗎?看來,T4模板是不要去,因爲併發模式是在CSDL不是在後面的代碼的方式..

回答

3

我看着EDMX文件之前和更改屬性的併發模式之後,用解想出了作爲一個控制檯應用程序,該應用程序從'timestamp'列的存儲模型開始解析edmx文件,並通過映射修改概念模型。這是一個相當強大的解決方案,但它有一些注意事項。

我正在使用MSSQL 2008,其中timestamp/rowversion是事實上的併發類型。在我的模型中,我只使用這種類型作爲併發令牌。如果您在其他地方使用它,但是爲所有併發令牌使用一致的名稱,那麼我已經包含了可以取消註釋的此場景的代碼。

  IEnumerable<XElement> storageEntities = 
      from el in ssdl.Descendants(XName.Get("EntityType",ssdlNS)) 
      where (from prop in el.Elements(XName.Get("Property",ssdlNS)) where prop.Attribute("Type").Value == "timestamp" select prop).Count()>0 
      select el; 

如果併發模式更加複雜,這段代碼榮獲:如果您僅使用一個不同的併發類型,該類型是唯一的併發列,可以在這行代碼更改從「時間戳」類型沒那麼多。這就是說,我在大約一個小時內把它攪起來,運行它,它對我有近200個實體的模型非常有用,通過緩慢的edmx設計器節省了我很多煩惱,所以我是肯定其他人會受益。這是一個控制檯應用程序,因此您可以將其放入模型項目的預建步驟中,以將其集成到構建過程中。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Xml; 
using System.Xml.Linq; 

namespace ConfigureConcurrency 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string edmxPath = args[0]; //or replace with a fixed path 

      if (edmxPath == null || edmxPath.Length == 0) 
       return; 

      string edmxNS = @"http://schemas.microsoft.com/ado/2008/10/edmx"; 
      string ssdlNS = @"http://schemas.microsoft.com/ado/2009/02/edm/ssdl"; 
      string csdlNS = @"http://schemas.microsoft.com/ado/2008/09/edm"; 
      string mapNS = @"http://schemas.microsoft.com/ado/2008/09/mapping/cs"; 

      XElement root = XElement.Load(edmxPath); 
      //Storage Model 
      XElement ssdl = root.Descendants(XName.Get("StorageModels", edmxNS)).FirstOrDefault(); 
      //Conceptual 
      XElement csdl = root.Descendants(XName.Get("ConceptualModels", edmxNS)).FirstOrDefault(); 
      //Mapping 
      XElement map = root.Descendants(XName.Get("Mappings", edmxNS)).FirstOrDefault(); 

      /* 
      Use this code instead of the line below it, if the type of your concurrency columns is used on other non-concurrency columns 
      and you use the same name for every concurrency column    

      string ConcurrencyColumnName = "RowVersion"; 
      IEnumerable<XElement> storageEntities = 
       from el in ssdl.Descendants(XName.Get("EntityType", ssdlNS)) 
       where (from prop in el.Elements(XName.Get("Property", ssdlNS)) where prop.Attribute("Name").Value == ConcurrencyColumnName select prop).Count() > 0 
       select el; 
      */ 

      IEnumerable<XElement> storageEntities = 
       from el in ssdl.Descendants(XName.Get("EntityType",ssdlNS)) 
       where (from prop in el.Elements(XName.Get("Property",ssdlNS)) where prop.Attribute("Type").Value == "timestamp" select prop).Count()>0 
       select el; 

      //for each timestamp column, find the mapping then find the conceptual model property and establish the concurrency mode 
      foreach(XElement storageEntity in storageEntities) 
      { 
       //Get the mapping 
       XElement mapping = (from el in map.Descendants(XName.Get("EntityTypeMapping",mapNS)) where el.Element(XName.Get("MappingFragment",mapNS)).Attribute("StoreEntitySet").Value == storageEntity.Attribute("Name").Value select el).FirstOrDefault(); 

       if (mapping != null) 
       { 
        //Get the column mapping 
        XElement column = (from el in storageEntity.Descendants(XName.Get("Property",ssdlNS)) where el.Attribute("Type").Value == "timestamp" select el).FirstOrDefault(); 
        string columnName = column.Attribute("Name").Value; 
        XElement columnMapping = (from el in mapping.Descendants(XName.Get("ScalarProperty",mapNS)) where el.Attribute("ColumnName").Value == columnName select el).FirstOrDefault(); 
        string propertyName = columnMapping.Attribute("Name").Value; 

        //Get the conceptual schema namespace and type name 
        string[] split = mapping.Attribute("TypeName").Value.Split('.'); 

        string ns="", typeName =split[split.Length-1]; 

        for (int i = 0; i < split.Length-1; i++) 
        { 
         if (i>0) 
          ns+="."; 

         ns += split[i]; 
        } 

        //Find the entry in the conceptual model 
        XElement schema = (from el in csdl.Elements(XName.Get("Schema",csdlNS)) where el.Attribute("Namespace").Value == ns select el).FirstOrDefault(); 

        if (schema != null) 
        { 
         //Find the entity type 
         XElement entity = (from el in schema.Descendants(XName.Get("EntityType",csdlNS)) where el.Attribute("Name").Value == typeName select el).FirstOrDefault(); 

         //Find the property 
         XElement concurrencyProperty = (from el in entity.Elements(XName.Get("Property",csdlNS)) where el.Attribute("Name").Value == propertyName select el).FirstOrDefault(); 

         //Set concurrency mode to fixed 
         concurrencyProperty.SetAttributeValue("ConcurrencyMode", "Fixed"); 
        } 
       } 
      } 

      //Save the modifications 
      root.Save(edmxPath); 


     } 
    } 
} 
1

解決了我上面的控制檯應用程序類似的問題。 但是,如果您運行的是更高版本的Entity Framework,請務必更新對模式的引用。我正在使用EF 5,對我而言,我使用了以下幾行:

string edmxNS = @"http://schemas.microsoft.com/ado/2009/11/edmx"; 
string ssdlNS = @"http://schemas.microsoft.com/ado/2009/11/edm/ssdl"; 
string csdlNS = @"http://schemas.microsoft.com/ado/2009/11/edm"; 
string mapNS = @"http://schemas.microsoft.com/ado/2009/11/mapping/cs"; 
相關問題