事实证明,在实现TPT(每种类型的表)继承时,我是发现微软实体框架中存在的基础底层的最后一个人。
构建了一个包含3个子类的原型,包含20多列的基表/类和包含~10列的子表,一切都运行得很漂亮,我继续研究其余的应用程序,证明了这个概念。现在是添加其他20个子类型和OMG的时候了,我刚刚开始查看在简单选择上生成的SQL,即使我只对访问基类上的字段感兴趣。
This page对问题进行了精彩描述。
有没有人使用TPT和EF投入生产,是否有任何变通办法,这意味着我不必: a)将模式转换为TPH(这与我尝试用我的数据库设计实现的所有内容相反 - urrrgghh!)? b)用另一个ORM重写?
我看到它的方式,我应该能够在EF(可能使用EFExtensions)中添加对存储过程的引用,该存储过程具有仅选择我需要的字段的TSQL,即使使用EF生成的代码也是如此SP内部的怪物UNION / JOIN会阻止每次调用时生成SQL - 这不是我打算做的事情,但是你明白了。
我发现的杀手是,当我选择链接到基表的实体列表时(但我选择的实体不是子类表),我想按pk过滤Base表,我.Include("BaseClassTableName")
允许我使用x=>x.BaseClass.PK == 1
进行过滤并访问其他属性,它也在这里执行母SQL生成。
我无法使用EF4,因为我仅限于安装了3.5 SP1的.net 2.0运行时。
有没有人有过摆脱这种混乱的经历?
答案 0 :(得分:2)
我们遇到了同样的问题,并且正在考虑将我们的DAL从EF4移植到LLBLGen因此。
与此同时,我们使用编译查询来缓解一些痛苦:
Compiled Queries (LINQ to Entities)
此策略不会阻止庞大的查询,但生成查询所需的时间(可能很大)只执行一次。
你可以使用带有Includes()的编译查询:
static readonly Func<AdventureWorksEntities, int, Subcomponent> subcomponentWithDetailsCompiledQuery = CompiledQuery.Compile<AdventureWorksEntities, int, Subcomponent>(
(ctx, id) => ctx.Subcomponents
.Include("SubcomponentType")
.Include("A.B.C.D")
.FirstOrDefault(s => s.Id == id));
public Subcomponent GetSubcomponentWithDetails(int id)
{
return subcomponentWithDetailsCompiledQuery.Invoke(ObjectContext, id);
}
答案 1 :(得分:1)
这似乎有点困惑。你在谈论TPH,但当你说:
我看到它的方式,我应该能够在EF(可能使用EFExtensions)中添加对存储过程的引用,该存储过程具有仅选择我需要的字段的TSQL,即使使用EF生成的代码也是如此SP内部的怪物UNION / JOIN会阻止每次调用时生成SQL - 这不是我打算做的事情,但是你明白了。
那么,这是每个具体类映射的表(使用proc而不是表,但仍然是映射是TPC ......)。 EF支持TPC,但设计师没有。 You can do it in code-first if you get the CTP
如果限制查询,首选的使用proc的解决方案将导致性能问题,如下所示:
var q = from c in Context.SomeChild
where c.SomeAssociation.Foo == foo
select c;
数据库优化器无法查看proc实现,因此您可以全面扫描结果。
因此,在您告诉自己这将修复您的结果之前,请仔细检查该假设。
请注意,您始终可以使用ObjectContext.ExecuteStoreQuery为任何映射策略指定自定义SQL。
但是,在执行任何此操作之前,请考虑一下,正如RPM1984指出的那样,您的设计似乎过度使用了继承。我喜欢this quote from NHibernate in Action
[A]了解自己是否可以更好地将继承重建为对象模型中的委托。由于与持久性或ORM无关的各种原因,通常可以最好地避免复杂继承。 [您的ORM]充当对象和关系模型之间的缓冲区,但这并不意味着您在设计对象模型时可以完全忽略持久性问题。