我有一个继承自DynamicObject
的基础对象,我将其用作实体POCO的基类,这允许POCO像ExpandoObject
一样工作({{1}像引擎盖下的对象)我将该字典映射到edm兼容的Key / Value类,如下所示:
Dictionary<string,object>
并为我们需要存储的每种系统类型提供强类型继承类,即
public class EntityPair<TKey, TValue>
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public TKey Key { get; set; }
public TValue Value { get; set; }
public string TableName { get; set; }
public int FK { get; set; }
}
并且基本expando有一个公共属性,它将获取类型的所有动态属性(如字符串),因为它是相应的键值类型。例如,对于字符串属性,它将返回public class EntityPairString: EntityPair<string,string> { }
个对象的集合。
现在我遇到的问题是它没有加载数据库的类型集合(如字符串集合)退出 - 我可以存储它。但是当我检索它时,我无法获得字符串KVPair集合。有什么奇怪的是EF说它知道关系,并加载了集合,但它没有设置集合 - 即使我急切地或明确地加载它。
实体:
EntityPairString
它继承的Expando:
public class Order : Expando
{
public Order()
{
TableName = "Order";
}
public short OrderType { get; set; }
public int InitiatorId { get; set; }
public string InitiatorName { get; set; }
[...]
public class OrderConfiguration : EntityTypeConfiguration<Order>
{
public OrderConfiguration()
{
Map(c => c.MapInheritedProperties());
HasMany(c => c.StringExpando)
.WithOptional()
.HasForeignKey(c => c.FK)
.WillCascadeOnDelete(true);
}
}
}
其他一切正常,就像我说的那样,我可以很好地为数据库添加值,没有发生的事情是从数据库中加载属性。 [Serializable]
public class Expando : DynamicObject, IDynamicMetaObjectProvider
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
protected string TableName { get; set; }
[...]
public virtual ICollection<EntityPairString> StringExpando
{
get
{
var values = ((IEnumerable<EntityPair<string, object>>)Properties)
.Where(c => c.Value is string)
.Select(d => new EntityPairString()
{
Key = d.Key,
Value = d.Value as string,
Id = d.Id,
FK = Id,
TableName = TableName
}).ToList();
return values;
}
set
{
if (Properties == null) Properties = new PropertyBag();
foreach (var i in value)
{
var p = (EntityPair<string, string>)i;
Properties.Add(new EntityPair<string, object>
{
Id = i.Id,
Key = i.Key,
Value = i.Value,
FK = Id,
TableName = TableName
});
}
}
}
}
对象返回正常,但它不会加载字符串expando属性。
注意:虽然Order
中的实体映射表明它是外键,但我从显式数据库迁移中删除了它。该关系已编入索引,并在运行时期间仍在EF的内部列表中列出。我通过致电:
Order.OrderConfiguration
所以简单来说,我的问题是,当我加载任何或所有var relationshipManager = ((IObjectContextAdapter) ctx).ObjectContext
.ObjectStateManager.GetRelationshipManager(order);
var relations = relationshipManager.GetAllRelatedEnds();
个实体时,为什么我的EntityPairString
集合没有被EF附加到Order
对象?
彻底性:
显式迁移的相关部分:
Order
更新:
就在我的调试过程中,我决定确认它正在生成正确的查询,所以我做了一个SQL配置文件,它运行的查询是:
CreateTable(
"dbo.expando_string",
c => new
{
Id = c.Int(nullable: false, identity: true),
TableName = c.String(nullable: false, maxLength: 128),
FK = c.Int(nullable: false),
Key = c.String(),
Value = c.String(),
})
.PrimaryKey(t => new { t.Id, t.TableName, t.FK })
.Index(t => t.FK);
在执行时会返回正确的结果集,所以在EF C#代码中的某个地方它只是没有附加实体。
答案 0 :(得分:0)
我弄清楚出了什么问题--EF没有设置集合,它只添加或删除它们,如果getter返回null,它将初始化一个集合,但是它仍然会添加到刚刚初始化的集合中(这就是为什么你可以在懒惰加载其余的集合之前添加一个项目)
所以问题在于:
public virtual ICollection<EntityPairString> StringExpando
{
get
{
var values = ((IEnumerable<EntityPair<string, object>>)Properties)
.Where(c => c.Value is string)
.Select(d => new EntityPairString()
{
Key = d.Key,
Value = d.Value as string,
Id = d.Id,
FK = Id,
TableName = TableName
}).ToList();
return values;
}
set
{
if (Properties == null) Properties = new PropertyBag();
foreach (var i in value)
{
var p = (EntityPair<string, string>)i;
Properties.Add(new EntityPair<string, object>
{
Id = i.Id,
Key = i.Key,
Value = i.Value,
FK = Id,
TableName = TableName
});
}
}
}
我必须进行一些重组,但我最终通过实际返回集合来实现它,所以当它添加到集合中时我会意识到它。
简单地说,这是我的一个愚蠢的错误,EF实际上已经为我设置了值,但是它将它们设置在我无法处理的列表中。
EF用于保存和获取集合的最终方法是什么:
public ICollection<ExpandoString> StringExpando
{
get
{
// ReSharper disable ForCanBeConvertedToForeach
for (var i = 0; i < _strings.Count; i++)
// ReSharper restore ForCanBeConvertedToForeach
{
_strings[i].FK = Id;
_strings[i].TableName = TableName;
}
//using for as we don't want to enumerate the bag
return _strings.List;
}
}
使用可扩展对象作为实体的唯一警告是,您必须明确加载可扩展实体上的所有关系,但是,它们将很轻,因此它不应该是一个交易破坏者。