自动化ConcurrencyMode设置EDMX修复(Automating ConcurrencyM

2019-09-21 06:50发布

在我们的模型我们的表的多数有一个名为“intConcurrencyID”我们打算使用并发检查现场。 我相信,以使这个领域在数据库优先环境并发检查的唯一途径是将并发模式设置为固定。

然而,如果我们每EDMX表的数量巨大,我们将有一个很难手动配置每单位每类不提一些实体被忽略的可能性。

你对我如何可以自动完成这一过程的任何想法? 看来,T4模板是不要去,因为并发模式是在CSDL不是在后面的代码的方式..

Answer 1:

我看着EDMX文件之前和更改属性的并发模式后,用溶液作为分析开始与“时间戳”列存储模型的EDMX文件并按照映射修改概念模型一个控制台应用程序上来。 这是一个相当强大的解决方案,但是它有一些注意事项。

我使用的是MSSQL 2008年,该时间戳/ 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);


        }
    }
}


Answer 2:

解决了我类似的问题与上面的控制台应用程序。 但是,如果你正在运行的实体框架的更高版本,一定要更新引用模式。 我使用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";


文章来源: Automating ConcurrencyMode set to Fix in EDMX