多个数据库,模型略有变化。 如何允许Entity Framework在运行时删除列?

这是对“ 具有轻微变化模型的多个数据库的跟进。如何允许EF在运行时使用不同的数据库结构? ”问题:

我正在使用.NET4.5MSSQLOracle.NET4.5在全公司(许多部门)全球使用的系统上查询属于我们部门的不同数据库,这些数据库大多数是相同的EF模型,一些数据库是Oracle和一些是Microsoft SQL ,有些是开发或uat,有些是日志。

我正在为OracleMSSQL数据库使用不同的EF模型。

一个要求是在运行时在数据库之间切换,这很容易,

public AggregatorEntities(string connectionString) : base(connectionString) { }

但它确实有副作用 – 许多数据库(dev,uat,dr,logs,…)与Live不同(模型是从Live生成的),这在查询这些数据库时会导致错误。

管理层了解情况,他们可以使用某个特定数据库的开发人员对全局查询系统进行更改,以便测试人员和uat查询数据。 但是,他们希望进行更改,以便花费最少的时间来完成此操作 – 因为每个涉及数据库更改的项目都需要额外的成本。 我基本上需要构建一个’可以处理所有’弹性系统,当一个人在EF更改数据库时,会做一些事情来适应特定的数据库。

有不同的故障情况:
1.表上列的名称相同但实体中的类型不同
2.表上没有列,但EF中有一个实体
3.桌面上不在EF上的其他列
4.数据库中不在EF模型中的其他表
5.数据库中没有表,但EF模型中有实体。

这是在运行时删除EF模型但不在数据库中的列的情况(上面的第3点)。

好的,所以我构建了这个讨厌的东西,允许在运行时从表中删除列。

1.您需要在DbContext*.edmx – > *.Context.tt – > *.Context.cs )中添加构造函数重载,如:

 public partial class EcomEntities : DbContext { public EcomEntities(DbConnection connection) : base(connection, true) { } public EcomEntities(string connectionString) : base(connectionString) { } 

2.您将需要数据库连接SystemToDatabaseMapping器(为了清楚起见,我在这里明确地硬编码参数,通常会从SystemToDatabaseMapping获取它们)。 ColumnsToRemove具有需要删除的表名和列名,EF connectionString 是自解释的 。

 public void ChangeConnection(SystemToDatabaseMapping systemToDatabaseMapping) { if (systemToDatabaseMapping.ColumnsToRemove != null) { var entityConnection = EntityConnectionExtensions.Create( new List { new ColumnsToRemove("QUOTE_HOUSE", "UPRN"), new ColumnsToRemove("QUOTE_HOUSE", "INSIGHT_DATA") }, systemToDatabaseMapping.ConnectionString); this.Ecom = new EcomEntities(entityConnection); } else { this.Ecom = new EcomEntities(systemToDatabaseMapping.ConnectionString); } .... } 

然后那个真正做出令人讨厌的事情的人就会从实体映射xmls中删除节点,然后再将它们提供给MetadataWorkspace

 using System.Collections.Generic; using System.Data.Common; using System.Data.Entity.Core.EntityClient; using System.Data.Entity.Core.Mapping; using System.Data.Entity.Core.Metadata.Edm; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using System.Xml; using System.Xml.Linq; public static class EntityConnectionExtensions { public static IEnumerable ElementsAnyNS(this IEnumerable source, string localName) where T : XContainer { return source.Elements().Where(e => e.Name.LocalName == localName); } public static IEnumerable ElementsAnyNS(this XContainer source, string localName) { return source.Elements().Where(e => e.Name.LocalName == localName); } private static void RemoveNodes(XElement element, List tableAndColumn) { if (element.Attribute("Name") != null && tableAndColumn.Any(oo => oo.Table == element.Attribute("Name").Value) || element.Attribute("StoreEntitySet") != null && tableAndColumn.Any(oo => oo.Table == element.Attribute("StoreEntitySet").Value)) { var matchingSelectParts = tableAndColumn.Where(oo => element.Value.Contains(string.Format("\"{0}\".\"{1}\" AS \"{1}\"", oo.Table, oo.Column))).ToList(); if (matchingSelectParts.Any()) { foreach (var matchingSelectPart in matchingSelectParts) { var definingQuery = element.ElementsAnyNS("DefiningQuery").Single(); definingQuery.Value = definingQuery.Value.Replace(string.Format(", \n\"{0}\".\"{1}\" AS \"{1}\"", matchingSelectPart.Table, matchingSelectPart.Column), ""); } } else { var nodes = element.Nodes() .Where(o => o is XElement && ((XElement) o).Attribute("Name") != null && tableAndColumn.Any(oo => ((XElement) o).Attribute("Name").Value == oo.Column)); foreach (var node in nodes.ToList()) { node.Remove(); } } } } public static EntityConnection Create(List tablesAndColumns, string connString) { var modelNameRegex = new Regex(@".*metadata=res:\/\/\*\/([a-zA-Z.]*).csdl|.*"); var model = modelNameRegex.Matches(connString).Cast().SelectMany(o => o.Groups.Cast().Skip(1).Where(oo => oo.Value != "")).Select(o => o.Value).First(); var conceptualReader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream(model + ".csdl")); var mappingReader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream(model + ".msl")); var storageReader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream(model + ".ssdl")); var conceptualXml = XElement.Load(conceptualReader); var mappingXml = XElement.Load(mappingReader); var storageXml = XElement.Load(storageReader); foreach (var entitySet in new[] {storageXml, conceptualXml}.SelectMany(xml => xml.Elements())) { if (entitySet.Attribute("Name").Value == "ModelStoreContainer") { foreach (var entityContainerEntitySet in entitySet.Elements()) { RemoveNodes(entityContainerEntitySet, tablesAndColumns); } } RemoveNodes(entitySet, tablesAndColumns); } foreach (var entitySet in mappingXml.Elements().ElementAt(0).Elements()) { if (entitySet.Name.LocalName == "EntitySetMapping") { foreach (var entityContainerEntitySet in entitySet.Elements().First().Elements()) { RemoveNodes(entityContainerEntitySet, tablesAndColumns); } } RemoveNodes(entitySet, tablesAndColumns); } var storageCollection = new StoreItemCollection(new [] {storageXml.CreateReader()}); var conceptualCollection = new EdmItemCollection(new[] { conceptualXml.CreateReader() }); var mappingCollection = new StorageMappingItemCollection(conceptualCollection, storageCollection, new[] {mappingXml.CreateReader()}); var workspace = new MetadataWorkspace(); workspace.RegisterItemCollection(conceptualCollection); workspace.RegisterItemCollection(storageCollection); workspace.RegisterItemCollection(mappingCollection); var connectionData = new EntityConnectionStringBuilder(connString); var connection = DbProviderFactories .GetFactory(connectionData.Provider) .CreateConnection(); connection.ConnectionString = connectionData.ProviderConnectionString; return new EntityConnection(workspace, connection); } } public class ColumnsToRemove { public ColumnsToRemove(string table, string column) { Table = table; Column = column; } public string Table { get; set; } public string Column { get; set; } } public class SystemToDatabaseMapping { public string ConnectionString { get; set; } public List ColumnsToRemove { get; set; } } 

希望这能为您节省一些时间。