具有大型系统的实体框架-如何划分模型?


50

我正在使用具有1000多个表,另外几百个视图和几千个存储过程的SQL Server数据库。我们希望开始在新项目中使用Entity Framework,并且正在制定策略。我最想知道的是如何最好地将表拆分为不同的模型(如果我们先编写代码,则为EDMX或DbContext)。我可以马上想到一些策略:

  • 按模式拆分
    我们将表拆分成大概十二种模式。我们可以为每个架构创建一个模型。但是,这并不是完美的,因为dbo最终仍然非常大,具有500多个表/视图。另一个问题是,某些工作单元最终将不得不进行跨越多个模型的事务,这增加了复杂性,尽管我认为EF使这一过程变得相当简单。
  • 按意图
    拆分模型不必担心架构,而是按意图拆分模型。因此,对于每个应用程序,项目,模块,屏幕,我们将具有不同的模型,具体取决于我们希望获得的粒度。我看到的问题是,在某些情况下不可避免地要使用某些表,例如User或AuditHistory。我们是将它们添加到每个模型中(违反我认为的DRY),还是将它们添加到每个项目使用的单独模型中?
  • 完全不要分裂-一个巨大的模型
    从开发的角度来看,这显然很简单,但是从我的研究和我的直觉来看,这似乎可以在设计时,编译时和运行时都表现出色。

在如此大的数据库上使用EF的最佳实践是什么?具体来说,人们在针对大量数据库对象设计模型时会使用哪些策略?是否有我没有想到的选项比上面的选项更好?

另外,这在诸如NHibernate的其他ORM中是否存在问题?如果是这样,他们是否提出了比EF更好的解决方案?


“必须执行跨多个模型的事务,这增加了复杂性”在此处仅需注意,您将需要启用Microsoft分布式事务处理协调器。一旦启动并运行它,就很容易完成您所说的事情。
Tjaart 2012年

@Tjaart谢谢。我曾经使用过MS DTC,尽管它非常简单,但它确实增加了简单DB txn之外的复杂性,因此我想尽可能避免使用它。
RationalGeek

2
4年后,您决定了什么,现在又建议什么?
罗里

Answers:


31

就个人而言,我曾尝试在一个相当复杂但规模较小的项目(约300张桌子)上为所有实体制作一个大型架构。我们有一个非常规范化的数据库(第5种形式的规范化(我说这很宽松)),它具有许多“多对多”关系和极端的参照完整性强制。

我们还使用了“每个请求一个实例”的策略,但我也不认为这对您有帮助。

当进行简单,合理的扁平“明确定义”清单时,查找和保存性能通常是可以接受的。但是,当我们开始深入探究深厚的关系时,表现似乎会急剧下降。与这种情况下的存储过程相比,没有任何比较(当然)。我确信我们可以在这里和那里调整代码库以提高性能,但是,在这种情况下,由于时间限制,我们只需要性能提升就可以不进行分析,而我们又退回了存储的proc(仍将其映射)通过EF,因为EF提供了强类型化的结果),所以我们只需要它作为回退到几个区域的结果。当我们不得不遍历整个数据库以创建一个集合(不加任何使用.include())时,性能明显下降,但是也许我们要求太多了。

因此,根据我的经验,我建议根据意图创建一个单独的.edmx。仅根据需要的范围生成您将要使用的内容。您可能有一些较小的作用域.edmx文件来完成有针对性的任务,然后有一些较大的文件需要遍历复杂的关系来构建对象。我不确定那个魔点在哪里,但是我肯定有一个...大声笑...

坦白地说,除了我们看到的一些陷阱(复杂遍历)之外,巨大的.edmx从“工作”的角度来看也可以正常工作。但是,如果您未明确禁用上下文,则必须注意上下文在后台进行的“修复”魔术。除了在更改数据库时使.edmx保持同步之外,有时还更容易擦除整个表面并重新创建实体,这大约需要3分钟,所以这没什么大不了的。

EntityFramework 4.1就是这样。我也很想听听您的最终选择和经验。

关于您在nHibernate上的问题,我认为这是一个蠕虫问题,您将在栅栏的两边咆哮...我听到很多人为扑打EF而扑朔迷离,而没有通过挑战和理解EF本身特有的细微差别。虽然我从未在生产中使用过nHibernate,但是通常来说,如果必须手动和显式创建诸如映射之类的内容,则将获得更有限的控制,但是,如果您可以使用LINQ拖放,生成并启动CRUD'ing和查询,我可以讲讲粒度。

我希望这有帮助。


1
仅供参考-有一个NHibernate映射实用程序,可以使这些映射非常容易且自动化。
ganders 2014年

@ganders-它具有UI以及IDE集成如何?我假设您将其指向数据源,并且它尊重参照完整性和对象遍历并创建映射对象?
hanzolo 2014年

1
是的(GUI)。到目前为止,我的问题是零。用于4或5个不同的项目/网站。注意:我将它与Fluent NHibernate一起使用,它以c#代码而不是config / xml文件的形式进行映射。这里有一个链接:nmg.codeplex.com
公鹅

13

让我从简单的澄清开始:我没有使用这么大的数据库的经验,所以我的其余答案不是基于真实的例子。

因此,您有一个BIG数据库,并且要与ORM / EF一起使用。我会选择第二个。这是我的简单解释,原因:

  • 映射增加了复杂性。无需为您当前的应用程序/项目/模块永远不需要的实体增加复杂性,而不必将粒度设置得太低。为每个屏幕设置单独的映射也无济于事。
  • 您想要实现工作单元。您应该能够指定大多数情况下需要哪些表模块(并非在所有情况下都必需)。如果将这些表放入单个映射集中,则可以通过单个上下文实例处理读取和数据修改-这才是您的最终目标。
  • 我不确定模型到底是什么意思,但是即使使用不同的映射集,您也可以使用相同的实体类型在映射集之间共享类。因此,如果在两个模块中使用User表,则不需要两个User类来表示相同的类。您仍然可以使用单个表,并且在代码映射的情况下(又称代码优先),您甚至可以定义一次映射并将其加载到多个映射集,因此不会违反DRY原理,但是代码优先方法在使用时会遇到更多限制查看和存储过程。EDMX使这变得更加困难。您仍然可以重用类,但无法重用映射。
  • 跨模块查询呢?这些查询可能会发生,但老实说,并非所有内容都必须由EF处理。在常见情况下,您可以利用EF来简化常规数据访问,但是如果您需要在某个地方进行特殊查询以连接属于5个不同模块的表,则可以直接执行它或将其包装在存储过程中。100%替换本机数据访问可能是困难,复杂和适得其反的。
  • 最后一点很实际:我不认为VS工具可以使用这么大的对象集-不是在设计器中,甚至是导入工具都没有。我曾经在VS2008中使用传统数据访问和SQL数据库项目来处理非常大的数据库-复杂项目的用户体验非常糟糕。您必须将使用的表的数量保持在低水平-设计器的上限应在100-200之间,但是即使单个上下文(映射集)处理的100个表听起来像是对一个类负责过多(假设您将拥有100个set属性)暴露在上下文中-它看起来不是一个好的设计)。

4

我会说您不能从技术角度决定这种问题。我建议您根据用例(用户案例等)构建体系结构。首先找到您的业务对象。缺省情况下,实体对象不是业务对象。通常,您将在实体对象前面有一个业务对象。然后,您可以根据用户要求逐步确定您真正需要什么。

“优秀的架构师可以使未做出的决定数量最大化。” 罗伯特·马丁

http://cleancoder.posterous.com/architecture-deference


3

我使用一种混合方法-OLTP内容由EF处理,而繁重的操作(如批处理插入,批量更新,报告查询等)由Stored Procs处理。如果您不打算一次全部重写数据层,这也使迁移路径更容易。


这似乎是一个不错的策略,但是并没有真正解决如何在不同EF模型之间划分实体的问题。您是否在一个模型中拥有所有实体,还是以某种方式进行分而治之?
RationalGeek

1
如果OLTP性能对于完整模型方法来说足够了,那就去吧。如有必要,您可以随时将其分解,但是最快,最敏捷的方法是加载整个内容。您可能永远不需要通过分解来获得性能提升,因此您会浪费时间并使系统无缘无故变得更加复杂。然后是一个问题,当您决定扩展时,您将坚持使用哪种新表/实体。当您需要跨多个模型运行更新时,会发生什么。除非您真的别无选择,否则请省去头痛。
Nik

忘了提一下,您随时可以在访问数据时调整性能。看一下懒惰/急切的加载选项以及要引入的子实体。如果您不加载大量的对象树,则没有理由认为完整的模型的行为比较小的模型要差。
Nik

我要说的是,大型对象树和规范化的数据结构在处理大型模式时会齐头并进
hanzolo 2012年

您可以控制要使对象图饱和的数量。
Nik
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.