entity framework实体不在DataSpace.OSpace(_workspace.GetItemCollection(DataSpace.OSpace))中,而是在DataSpace.CSpace中

我一直在使用XML for entity Framework。 我试图创建一种可以在运行时注入属性的实体,首先我创建了动态的DynamicEntity对象

 public class DynamicEntity : DynamicObject { Dictionary dynamicMembers = new Dictionary(); public override bool TrySetMember(SetMemberBinder binder, object value) { dynamicMembers[binder.Name] = value; return true; } public override bool TryGetMember(GetMemberBinder binder, out object result) { if (dynamicMembers.TryGetValue(binder.Name, out result)) { return dynamicMembers.TryGetValue(binder.Name, out result); } result = ""; return true; } } 

然后实体inheritance自此

public partial class QUOTE_HOUSE : DynamicEntity

(当我从db获取数据后手动设置属性时,它似乎确实有效)。

所以基于这种删除属性的机制,我试图做另一个将属性插入到XML中的东西,并且整个事情似乎保持不错(至少它不会破坏映射,它通常在XML不正确时执行var mappingCollection = new StorageMappingItemCollection(conceptualCollection, storageCollection, new[] {mappingXml.CreateReader()}); )。

执行查询时出现问题是EF

实体类型QUOTE_HOUSE不是当前上下文的模型的一部分。

描述:执行当前Web请求期间发生未处理的exception。 请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

exception详细信息:System.InvalidOperationException:实体类型QUOTE_HOUSE不是当前上下文的模型的一部分。

[InvalidOperationException:实体类型QUOTE_HOUSE不是当前上下文模型的一部分。]
System.Data.Entity.Internal.InternalContext.UpdateEntitySetMappingsForType(Type entityType)+208
System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)+50

在为EF加载pdb后,我在System.Data.Entity.Internal.InternalContext跟踪了TryUpdateEntitySetMappingsForType

基本上我的QUOTE_HOUSE不在this._workspace.GetItemCollection(DataSpace.OSpace)UpdateEntitySetMappings尝试从中映射它。

它检查它是否在this._entitySetMappingsCache.ContainsKey(entityType))并且因为它不是它然后尝试更新映射迭代this._workspace.GetItemCollection(DataSpace.OSpace)我的项目不存在

但是我可以看到我的实体确实存在于this._workspace.GetItems(DataSpace.CSpace)

完整的UpdateEntitySetMappings如下所示:

 private void UpdateEntitySetMappings() { ObjectItemCollection objectItemCollection = (ObjectItemCollection) this._workspace.GetItemCollection(DataSpace.OSpace); ReadOnlyCollection items = this._workspace.GetItems(DataSpace.OSpace); Stack entityTypeStack = new Stack(); foreach (EntityType entityType1 in items) { entityTypeStack.Clear(); EntityType cspaceType = (EntityType) this._workspace.GetEdmSpaceType((StructuralType) entityType1); do { entityTypeStack.Push(cspaceType); cspaceType = (EntityType) cspaceType.BaseType; } while (cspaceType != null); EntitySet entitySet = (EntitySet) null; while (entitySet == null && entityTypeStack.Count > 0) { cspaceType = entityTypeStack.Pop(); foreach (EntityContainer entityContainer in this._workspace.GetItems(DataSpace.CSpace)) { List list = entityContainer.BaseEntitySets.Where((Func) (s => s.ElementType == cspaceType)).ToList(); int count = list.Count; if (count > 1 || count == 1 && entitySet != null) throw Error.DbContext_MESTNotSupported(); if (count == 1) entitySet = (EntitySet) list[0]; } } if (entitySet != null) { EntityType entityType2 = (EntityType) this._workspace.GetObjectSpaceType((StructuralType) cspaceType); Type clrType1 = objectItemCollection.GetClrType((StructuralType) entityType1); Type clrType2 = objectItemCollection.GetClrType((StructuralType) entityType2); this._entitySetMappingsCache[clrType1] = new EntitySetTypePair(entitySet, clrType2); } } } 

实体如何进入this._workspace.GetItemCollection(DataSpace.OSpace)? 为什么实体会在CSpace而不在OSpace

编辑:对于那些可能想要获得赏金的人,下面是您可能需要设置环境来重现问题的组件。

 public class SystemToDatabaseMapping { public SystemToDatabaseMapping(string system, string databaseType, string database, string connectionString, Type enitityType) { System = system; Database = database; DatabaseType = databaseType; ConnectionString = connectionString; EntityType = enitityType; } public Type EntityType { get; set; } public string System { get; set; } public string Database { get; set; } public string DatabaseType { get; set; } public string ConnectionString { get; set; } public List ColumnsToModify { get; set; } } public abstract class ColumnToModify { protected ColumnToModify(string table, string column) { Table = table; Column = column; } public string Table { get; set; } public string Column { get; set; } public abstract bool IsRemove{ get; } } public class ColumnToRemove : ColumnToModify { public ColumnToRemove(string table, string column) : base(table, column) { } public override bool IsRemove { get { return true; } } } public class ColumnToAdd : ColumnToModify { public ColumnToAdd(string table, string column, Type type) : base(table, column) { this.Type = type; } public override bool IsRemove { get { return false; } } public Type Type { get; set; } } 

首先从db生成的实体,( DynamicEntity代码在上面)

 public partial class QUOTE_HOUSE : DynamicEntity { public long UNIQUE_ID { get; set; } } 

数据库的DbContext需要构造函数重载

  public partial class EcomEntities : DbContext { public EcomEntities(DbConnection connectionString) : base(connectionString, false) { } public virtual DbSet QUOTE_HOUSE { get; set; } .... } 

进行色谱柱注射的机制(它是一个粗略的原型,所以对它的外观有多么容易),当注入try string column我知道它映射好了。

 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 ModifyNodes(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 matchingRemoveSelectParts = tableAndColumn.Where(oo => oo.IsRemove && element.Value.Contains(string.Format("\"{0}\".\"{1}\" AS \"{1}\"", oo.Table, oo.Column))).ToList(); if (matchingRemoveSelectParts.Any()) { foreach (var matchingRemoveSelectPart in matchingRemoveSelectParts) { var definingQuery = element.ElementsAnyNS("DefiningQuery").Single(); definingQuery.Value = definingQuery.Value.Replace(string.Format(", \n\"{0}\".\"{1}\" AS \"{1}\"", matchingRemoveSelectPart.Table, matchingRemoveSelectPart.Column), ""); } } else { var nodesToRemove = element.Nodes() .Where(o => o is XElement && ((XElement) o).Attribute("Name") != null && tableAndColumn.Any(oo => oo.IsRemove && ((XElement) o).Attribute("Name").Value == oo.Column)); foreach (var node in nodesToRemove.ToList()) { node.Remove(); } if (element.Attribute("Name") != null && tableAndColumn.Any(oo => oo.Table == element.Attribute("Name").Value)) { var elementsToAdd = tableAndColumn.Where(o => !o.IsRemove && o.Table == element.Attribute("Name").Value); if (new[] {"Type=\"number\"", "Type=\"varchar2\"", "Type=\"date\""}.Any(o => element.ToString().Contains(o))) { foreach (var columnToModify in elementsToAdd) { var columnToAdd = (ColumnToAdd) columnToModify; var type = new[] {typeof (decimal), typeof (float), typeof (int), typeof (bool)}.Contains(columnToAdd.Type) ? "number" : columnToAdd.Type == typeof (DateTime) ? "date" : "varchar2"; var precision = ""; var scale = ""; var maxLength = ""; if (type == "number") { precision = "38"; scale = new[] {typeof (decimal), typeof (float)}.Contains(columnToAdd.Type) ? "2" : "0"; } if (type == "varchar2") { maxLength = "500"; } var newProperty = new XElement(element.GetDefaultNamespace() + "Property", new XAttribute("Name", columnToAdd.Column), new XAttribute("Type", type)); if (!string.IsNullOrWhiteSpace(precision)) { newProperty.Add(new XAttribute("Precision", precision)); } if (!string.IsNullOrWhiteSpace(scale)) { newProperty.Add(new XAttribute("Scale", scale)); } if (!string.IsNullOrWhiteSpace(maxLength)) { newProperty.Add(new XAttribute("MaxLength", maxLength)); } element.Add(newProperty); } } else if ( new[] {"Type=\"Decimal\"", "Type=\"String\"", "Type=\"DateTime\"", "Type=\"Boolean\"", "Type=\"Byte\"", "Type=\"Int16\"", "Type=\"Int32\"", "Type=\"Int64\""}.Any( o => element.ToString().Contains(o))) { foreach (var columnToModify in elementsToAdd) { var columnToAdd = (ColumnToAdd) columnToModify; var type = new[] {typeof (decimal), typeof (float), typeof (int), typeof (bool)}.Contains(columnToAdd.Type) ? "Decimal" : columnToAdd.Type == typeof (DateTime) ? "DateTime" : "String"; var precision = ""; var scale = ""; var maxLength = ""; if (type == "Decimal") { precision = "38"; scale = new[] {typeof (decimal), typeof (float)}.Contains(columnToAdd.Type) ? "2" : "0"; } if (type == "String") { maxLength = "500"; } var newProperty = new XElement(element.GetDefaultNamespace() + "Property", new XAttribute("Name", columnToAdd.Column), new XAttribute("Type", type)); if (!string.IsNullOrWhiteSpace(precision)) { newProperty.Add(new XAttribute("Precision", precision)); } if (!string.IsNullOrWhiteSpace(scale)) { newProperty.Add(new XAttribute("Scale", scale)); } if (!string.IsNullOrWhiteSpace(maxLength)) { newProperty.Add(new XAttribute("MaxLength", maxLength)); newProperty.Add(new XAttribute("FixedLength", "false")); newProperty.Add(new XAttribute("Unicode", "false")); } element.Add(newProperty); } } } } if (element.Attribute("Name") != null && tableAndColumn.Any(oo => oo.Table == element.Attribute("Name").Value) && element.GetNamespaceOfPrefix("store") != null && element.Attribute(element.GetNamespaceOfPrefix("store") + "Type") != null && element.Attribute(element.GetNamespaceOfPrefix("store") + "Type").Value == "Tables") { var matchingAddSelectParts = tableAndColumn.Where(o => !o.IsRemove && o.Table == element.Attribute("Name").Value); foreach (var matchingAddSelectPart in matchingAddSelectParts) { var definingQuery = element.ElementsAnyNS("DefiningQuery").Single(); var schemaRegex = new Regex(string.Format("\\nFROM \\\"([a-zA-Z0-9]*)\\\".\\\"{0}\\\"", matchingAddSelectPart.Table)); var schema = schemaRegex.Matches(definingQuery.Value)[0].Groups[1].Value; definingQuery.Value = definingQuery.Value.Replace( string.Format("\nFROM \"{0}\".\"{1}\" \"{1}\"", schema, matchingAddSelectPart.Table), string.Format(", \n\"{0}\".\"{1}\" AS \"{1}\"\nFROM \"{2}\".\"{0}\" \"{0}\"", matchingAddSelectPart.Table, matchingAddSelectPart.Column, schema)); } } if (element.Attribute("StoreEntitySet") != null && tableAndColumn.Any(oo => !oo.IsRemove && oo.Table == element.Attribute("StoreEntitySet").Value)) { var matchingAddSelectParts = tableAndColumn.Where(o => !o.IsRemove && o.Table == element.Attribute("StoreEntitySet").Value); foreach (var matchingAddSelectPart in matchingAddSelectParts) { element.Add(new XElement(element.GetDefaultNamespace() + "ScalarProperty", new XAttribute("Name", matchingAddSelectPart.Column), new XAttribute("ColumnName", matchingAddSelectPart.Column))); } } } } 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()) { ModifyNodes(entityContainerEntitySet, tablesAndColumns); } } ModifyNodes(entitySet, tablesAndColumns); } foreach (var entitySet in mappingXml.Elements().ElementAt(0).Elements()) { if (entitySet.Name.LocalName == "EntitySetMapping") { foreach (var entityContainerEntitySet in entitySet.Elements().First().Elements()) { ModifyNodes(entityContainerEntitySet, tablesAndColumns); } } ModifyNodes(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 ActionResult QUOTE_HOUSE() { var onlineDocs = Enumerable.Empty(); var mappings = new List{new SagaSystemToDatabaseMapping("x", "Oracle", "Db1", "metadata=res://*/Ecom.Ecom.csdl|res://*/Ecom.Ecom.ssdl|res://*/Ecom.Ecom.msl;provider=Oracle.ManagedDataAccess.Client;provider connection string='...'", typeof(EcomEntities)) { ColumnsToModify = new List { new ColumnToAdd("QUOTE_HOUSE","TESTCOL", typeof(string)) } }}; var entityConnection = EntityConnectionExtensions.Create(mappings[0].ColumnsToModify,mappings[0].ConnectionString); using (var db = new EcomEntities(entityConnection)) { onlineDocs = db.QUOTE_HOUSE.Take(10); } return View("QUOTE_HOUSE", onlineDocs.ToList()); } 

你应该能够从实体QUOTE_HOUSE生成oracle数据库并输入一些虚拟值,不要认为你需要一个视图,因为它会爆炸.ToList() 。 生成数据库后,向数据库添加附加列但不alter table QUOTE_HOUSE add TESTCOL Varchar2(20)模型( alter table QUOTE_HOUSE add TESTCOL Varchar2(20) ) – 使数据库中的列在运行时在模型中注入。 您可能还需要在此处调试EF程序集的方法 。 如果您需要更多信息或我错过了什么,请告诉我。

我知道这可能不是你所期待的,但我想至少它可以帮助你不浪费更多时间在那个方向。

好消息是问题不是由你的“hackish”代码引起的。 事实上,我能够在不使用该代码的情况下重现该问题。 刚刚创建了一个包含TestColQUOTE_HOUSE表,将其导入到新的edmx上下文中,只是从实体类中删除了生成的TestCol属性。 然后我让这个类inheritance了DynamicEntity ,使用默认的构造函数创建了一个上下文,名为context.QUOTE_HOUSE.ToList() ,它用相同的exception爆炸了。

坏消息是你想要实现的目标是不可能的。 EF只使用映射“对象空间”成员的reflection。 它不提供任何类型的扩展机制,例如TypeDescriptor ,或动态运行时(它甚至不允许您投影到动态对象)。 后者是可以理解的,因为每个动态对象可能具有不同的属性,并且没有动态类型这样的东西。 请注意,在运行时“删除”列的技巧NotMapped ,因为它的作用基本上与在代码中首先使用NotMapped相同,即属性确实存在,但被EF忽略。

如果您对实体在CSpace但不在OSpace中的原因感兴趣,则答案包含在名为OSpaceTypeFactory的内部类(在System.Data.Entity.Core.Metadata.Edm命名空间内) – 源中 。 有一个名为TryCreateStructuralType的方法,它调用TryCreateMembers ,如果返回false ,则不添加类型。 TryCreateMembers轮流调用TryFindAndCreatePrimitiveProperties ,传递使用reflection提取的PropertyInfo列表,如果无法将任何 CSpace成员映射到OSpace对象属性,则后者返回false ,从而有效地防止将类型添加到OSpace类型集合中。

希望至少能满足你的好奇心:)但是,再次,在运行时向EF实体“添加”属性是不幸的想法。