我正在开发一个复合的整个系统应用程序,不同的公司可能会添加不同的模块,但只有一个数据库。我的框架中有一个Generic存储库,它是独立于技术的(我的意思是它的提供者) base和现在的defult提供者是EF 4.1)。我已经分离了包含poco实体的公共层,并且在它们自己的程序集中每个模块也有不同的实体。 现在问题是实体映射。我不能从我的EF提供者项目访问我的实体,因为我不知道未来的模块!那么如何以通用方法映射我的实体呢?有可能吗?
我认为有一个解决方案是拥有一个配置文件并添加实体FullName然后进行迭代并反映每一个然后我可以在OnModelCreat(...)方法中添加它们,但是当然存在一些性能问题。
编辑: 首先感谢Ladislav的回复。 但是还有一些信息可供你使用。
您可以要求每个模块必须包含映射 它使用的每个新实体的类。当您启动应用程序时 你将只使用反射来获得所有派生的类 StructuralTypeConfiguration<> (包括实体和复合体 类型),创建这些类型的实例并将它们添加到配置 DbModelBuilder中的集合(可以在OnModelCreating中完成)。
这需要一些时间,但只有在上下文时才会发生一次 第一次使用。您可以在此期间触发此创建 应用程序启动 - 应用程序只需要一些时间来启动和 配置他们需要使用的所有基础设施。
编辑:
我必须在每个模块中引用EntityFramework.dll,在这种情况下不适合。
是。您希望允许其他开发人员定义自己的实体 这将由您的核心应用程序保留。在这种情况下他们 必须使用您选择的持久性框架来告诉您的应用程序 如何坚持自己的实体。
==> 正如我之前提到的,EF不是我唯一的DataProvider!我必须有一些其他的DP,例如DB4O等的数据提供者,所以我不想引用每个提供者对每个模块的依赖...因此我需要将EF封装在一个单独的程序集中
如果使用存储库,每个模块甚至应该包含它自己的存储库 用于处理自己的实体的存储库 - 通用存储库 不存在。通用存储库是冗余无用的层 只能更加努力地使用您选择的ORM。说清楚 - 正确实施存储库模式不是通用的。它是特定的,它为单个实体或公开数据访问功能 聚合根。
==> 我可以要求任何可靠的参考吗?为什么我应该为每个模块添加一个存储库,以防只有一个存储库可以满足我的所有要求?这是多余的? 在我的oppenion中使用特定或通用代表在正确的情况下都是正确的。我的模块中有90%具有来自存储库的相同要求,并且所有模块都应该具有CRUD ......
如果你不想在模块中使用EF依赖,要么根本不使用EF 或者定义您自己的中间映射层,它将被转换 在你的应用程序中的特定映射 - 很多工作与零 增值。
==> 事实上,我正在尝试定义自己的地图图层,因为我需要在我的应用程序架构中使用它。对我来说这没用。这是我询问如何实现它的唯一原因。我'我正在寻找最佳解决方案,我希望你能帮我把它交给它:)
其他选项根本就是不允许您的模块使用新实体 因为它看起来更像你当前的期望。如果模块 开发人员必须为他必须的实体定义新的数据库表 也能够使用持久性和定义之间的映射 桌子和他的实体。
==> 好主意但不适合我的情况;)
我必须在启动时反映每个模块dll,这意味着需要反映很多重要的dll,并且......还有其他想法吗?
你有没有见过Photoshop,Visual Studio等应用程序 MS Office应用程序在启动期间?你觉得怎么样? 当你看到闪屏时发生?应用程序正在初始化 - 它 正在加载和初始化其功能和插件。甚至服务器 应用程序可能需要几分钟才能完全启动。你正在建设 模块化应用程序(非复合)因此您必须为此付费 要求。
==&GT; 是的,我想我看到了其中的一些!如果他们在启动时加载例如所有托盘或侧边栏,他们必须雇用我。亲爱的微软,如果你不知道什么是延迟加载我可以帮助你提高你的表现:) < / p>
如果你不想使用反射,你可以使用MEF 建设模块化基础设施。
==&gt; 我已经使用Prism和MEF来处理模块化,但仅限于不适用于我的提供商的模块......
听起来EF对企业复合应用程序来说不是一个好的解决方案吗?
您没有提出任何不应该的企业要求 由EF实现。你只是打算满足你的期望 模块开发人员使用新实体但不能赋予他们能力 描述这些实体将如何被持久化 - 但谁会描述 它?
==&GT; 模型或中间映射器层将在每个模块加载并映射实体,如果EF支持(我不知道)我需要像bootstrapper一样的每个提供程序映射实体:)
您没有构建复合应用程序。复合应用 采用现有功能(组件,现有应用程序) 单独工作并将它们合成到一个新的应用程序。你是 构建模块化应用程序,您的核心可以托管其他模块 但是如果没有托管基础设施,这些模块就无法运行。
==&gt; 我不会就我的应用及其架构进行演讲,但我认为这就足以让您知道这是一个复合/模块化应用...
我应该切换到Model First吗?!!
模型第一(和EDMX一般)真的不适合你 期望,因为在模型的情况下,每个模块都需要它 拥有EDMX文件及其自己的上下文。
==&GT; 但是我可以在运行时更改EDMX文件的模型和xml吗?
您也不能首先使用代码自动生成数据库 因为任何新模块都会破坏你的应用程序或EF会 删除当前的数据库。
==&GT; 感谢您的建议,虽然我之前已经知道但是当然我会更加关注它。
答案 0 :(得分:2)
您可以要求每个模块必须包含它使用的每个新实体的映射类。当您启动应用程序时,您将只使用反射来获取从StructuralTypeConfiguration<>
派生的所有类(包括实体和复杂类型),创建这些类型的实例并将它们添加到Configurations
集合中DbModelBuilder
}(可以在OnModelCreating
中完成。)
这需要一些时间,但只有在第一次使用上下文时才会发生一次。您可以在应用程序启动期间触发此创建 - 应用程序只需要一些时间来启动和配置他们需要使用的所有基础架构。
修改强>
我必须在每个模块中引用EntityFramework.dll,在这种情况下不适合。
是。您希望允许其他开发人员定义他们自己的实体,这些实体将由您的核心应用程序保留。在这种情况下,他们必须使用您选择的持久性框架来告诉您的应用程序如何持久保存其实体。
如果使用存储库,每个模块甚至应该包含自己的存储库以便与自己的实体一起工作 - 通用存储库不存在。通用存储库是冗余的无用层,它只能使您选择的ORM更加困难。为了说清楚 - 存储库模式的正确实现不是通用的。它是特定的,它公开了单个实体或聚合根的数据访问功能。
如果你不想在模块中使用EF依赖,或者根本不使用EF,或者定义你自己的中间映射层,它将被转换为应用程序中的特定映射 - 很多工作都添加了零值。
其他选项根本就是不允许您的模块使用新实体,因为它看起来更像您当前的期望。如果模块开发人员必须为他的实体定义新的数据库表,那么他还必须能够使用持久性并定义表和他的实体之间的映射。
我必须在启动时反映每个模块dll,这意味着需要反映很多重要的dll,并且......还有其他想法吗?
你有没有在创业过程中看过像Photoshop,Visual Studio甚至MS Office应用程序这样的应用程序?当你看到闪屏时,你认为发生了什么?应用程序正在初始化 - 它正在加载并初始化其功能和插件。甚至服务器应用程序也需要几分钟才能完全启动。您正在构建模块化应用程序(非复合),因此您必须支付该要求。
如果您不想反思自己,可以使用MEF来构建模块化基础设施。
听起来EF对企业复合应用程序来说不是一个好的解决方案吗?
您没有提出任何不应由EF履行的企业要求。您只是满足于您的期望,允许模块开发人员使用新实体,但不能让他们能够描述这些实体将如何保留 - 但是谁会描述它?
您没有构建复合应用程序。复合应用程序采用单独工作的现有功能(组件,现有应用程序)和组合到新应用程序。您正在构建模块化应用程序,其中您的核心可以托管另一个模块,但这些模块无法在没有托管基础架构的情况下运行。
我应该切换到Model First吗?!!
模型优先(和EDMX一般)真的不适合您的期望,因为在模型的情况下,每个模块都需要自己的EDMX文件和它自己的上下文。
您也不能首先使用代码自动生成数据库,因为任何新模块都会破坏您的应用程序,否则EF将删除您当前的数据库。
上次修改,因为这不是讨论论坛:
EF不是我唯一的DataProvider!我必须有一些其他的DP,比如......
我不知道你为什么这样做,但这是错误的。单个应用程序(甚至模块化)应使用单个提供程序(ORM映射程序)。如果由于某些遗留代码而有其他数据提供者,那么就应该为所有新代码建立单一提供者策略。否则,您正在使用过度架构的应用程序而不是EF。在这种情况下,您的模块将始终只使用提供者的单一依赖。
我可以要求任何可靠的参考吗?!为什么我要为每个添加一个存储库 模块以防只有一个存储库可以满足我的所有要求? 这是多余的?
参考是体验。关于存储库和EF有数百个问题。如果要充分利用EF,通用存储库将不允许它,或者必须公开其他提供程序的实现中不可用的功能。如果您仅使用存储库为单个实体公开CRUD,那么您只需要包含IDbSet
已提供的内容。我知道您正在使用存储库隐藏您的提供商地狱。
事实上,我正在尝试定义自己的地图图层,因为我需要在我的应用程序架构中使用它。对我来说没用。
您将为每个提供程序特定的映射编写一些自定义映射(可能是XML)和转换器。我不确定你期望什么更好的答案 - 除了它不是一个好的方法。
模型或中间映射器层将在每个模块中加载并映射实体,如果EF支持(我不知道)我需要像每个提供程序的引导程序一样来映射实体
不缺少EF的一部分。它完全超出了EF的范围。由EF定义的任何中间层仍将是EF的一部分,并且不受其他工具的支持。 EF可以在创建模型时加载实体,但要加载它们,你必须告诉EF它们的存在以及如何映射它们 - 这就是我最初的答案所解释的。
我不会就我的应用及其架构进行演讲,但我认为这足以让您知道这是一个复合/模块化应用
可能是,但复合部件没有这些挑战,因为复合应用程序的每个组件都独立于其余组件,并且可以使用完全不同的持久性。您面临的挑战是每个模块化组件的内部。
但我可以在运行时更改EDMX文件的模型和xml吗?
试试吧。提示:没有公共API可以在低级别上使用此XML进行操作,并且没有公共API来修改加载的模型。可以在加载之前更改EDMX,但这通常意味着为SSDL,MSL和CSDL编写自定义解析器和xml构建器。您将拥有一组由所有已安装模块更新的映射文件。您还必须编写反向操作代码以卸载模块并正确删除映射中的所有功能。任何错误都可能破坏整个应用程序,因为映射将被破坏。我最初的想法是加载配置代码映射将花费你不到一天。构建它需要多长时间?
如果您想这样,请完全从项目中删除EF并开始使用NHibernate和hbm
映射文件。模块开发人员将使用模块逻辑和新实体,数据库表脚本和每个实体的hbm文件创建程序集。模块安装将创建表,将组件添加到模块位置并将hbm文件添加到映射拾取目录。您的NHibernate会话将加载该目录中的所有映射文件。