如何在我的DAL内部创建我的EF代码优先类的某些属性?

时间:2014-02-01 00:48:11

标签: c# linq entity-framework linq-to-entities repository-pattern

this blog post titled "Pragmatic Linq"中,Marc Gravell讨论了如何以允许在数据访问层(DAL)中使用Linq到实体的方式实现存储库模式,而不允许实现细节泄漏到DAL,并且不会很难正确测试DAL。

Mark提出的问题之一是DAL类通常包含导航属性,在大多数情况下,它不应该是公共API的一部分:

  

导航属性...非常快速地开始交叉聚合和/或导致懒惰行为(如果您的上下文不再存在则不太好)

传统上,可以通过创建一组用于DAL的类(具有EF导航属性)以及在DAL的公共API中使用的另一组类(没有导航属性)来解决这个问题。但是,马克不赞成这种做法:

  

我真的不想申报和维护“纯粹”(即与DAL分开)对象模型

他建议可以使用一组类,但将导航属性保留在存储库内部:

  

我目前的想法是......大多数导航属性应该标记为数据层的内部属性。这意味着您的存储库实现可以使用导航属性来构建有趣的查询,但是返回给调用者的公共API不包含它们。如果调用者从订单存储库获取并订购,并且想要了解客户的详细信息:艰难 - 去询问客户存储库。

这对我来说听起来不错 - 实际上,我花了几个小时试图以这种方式重构我的DAL。但是,在完成所有编译并开始运行/测试之后,我发现了一个问题。

我正在使用实体框架代码优先(EF6,如果它很重要)来持久化实体,并且我在我的实体类中标记为internal我不想成为其中的任何属性我的DAL的公共API。 (我已将我的数据访问代码移动到一个单独的程序集中,因此internal实际上意味着什么。)

但事实证明,Entity Framework会忽略任何标记为internal的属性!例如,我有一个整数FooId属性,我在内部使用,我不想公开,所以我将其标记为internal。现在,如果我允许EF重新创建我的数据库,它不会在相关表上创建FooId列。

更糟糕的是,如果导航属性标记为internal,它现在不再在相应的表之间创建外键关系。我想它将不再支持那些导航属性的延迟加载,尽管我没有测试过。

我是否误解了马克提出的建议?还有另一种方法可以将某些属性保留在DAL内部,但EF完全支持吗?

例如,我可以创建一个基类,用于仅具有公共属性的API,然后使用内部使用(和EF)的额外属性的派生类吗?听起来它可能会起作用,但之后我会有一个命名冲突(我希望我的API使用类似“Customer”的有意义名称的类,但我也希望我的内部类称为“Customer”所以EF会创建一个明智的数据库表。我想我可以通过覆盖约定强制表名,但仍然......)。

3 个答案:

答案 0 :(得分:3)

默认情况下,Code First将在模型中包含公共属性。但您可以使用FluentAPI映射内部属性。您甚至可以通过这种方式映射私有属性(如果您查看该情况下所需的额外步骤的引用)。

protected override void OnModelCreating(DbModelBuilder modelBuilder)

    {
        modelBuilder.Entity<User>().HasMany(x => x.Projects);
    }

参考文献:

http://blog.oneunicorn.com/2012/03/26/code-first-data-annotations-on-non-public-properties/

http://romiller.com/2013/01/23/ef6-code-first-mapping-all-private-properties-using-custom-conventions/

按惯例,BTW FooID将是名为Foo

的导航属性的外键

答案 1 :(得分:1)

EF并没有忽略导航属性,但它无法在没有特权的情况下反映出来。添加它会增加在受信任模式下运行EF的要求,这是另一种蠕虫。我可以通过两种方式来解决这个问题,我从未尝试过这两种方式。

在编译时编织属性。

使用此方法,您可以将internal属性编译为dll中的public属性。这样EF可以反映属性。但是,由于您的来源仍使用internal,因此您知道您的业务层不会有引用这些属性的来源。

这种方法的缺点是,当您通过dll而不是项目引用它时它不起作用。

您可以使用多种技术实现此目标,例如Fody/PublicizePostSharp

EntityMapper<>班级

中明确映射您的媒体资源

顾名思义,您明确地映射了您的属性,以便EF不需要反映您的类,以便能够找到属性。

理论上,EF应该能够使用Expressions.PropertyExpression来完成所需的所有设置/获取操作。以及覆盖代理类的相关属性。在实践中,我不太确定。

答案 2 :(得分:-3)

我认为您误解了导航属性的含义。见http://msdn.microsoft.com/en-us/library/vstudio/bb387104%28v=vs.100%29.aspx