2

我正在开发一个复合整体系统应用程序,不同的公司可能会添加不同的模块,但只有一个数据库。我的框架中有一个通用存储库,它是技术独立的(我的意思是它是提供者基础,现在默认提供者是 EF 4.1)。我已经分离了包含 poco 实体的公共层,并且每个模块在它们自己的程序集中也有不同的实体。现在的问题是实体映射。我无法从我的 EF 提供程序项目中访问我的实体,因为我不知道未来的模块!那么如何以通用方法映射我的实体?可能吗?

我认为一种解决方案是拥有一个配置文件并添加实体 FullName 然后迭代和反映每个实体,然后我可以将它们添加到 OnModelCreat(...) 方法中,但当然存在一些性能问题。

编辑:首先感谢您的回复 Ladislav。但是还有更多信息给你。

您可以要求每个模块必须包含它使用的每个新实体的映射类。当您启动应用程序时,您将只使用反射来获取从 StructuralTypeConfiguration<> 派生的所有类(包括实体和复杂类型),创建这些类型的实例并将它们添加到 DbModelBuilder 中的 Configurations 集合中(可以在 OnModelCreating 中完成)。

这将需要一些时间,但它只会在第一次使用上下文时发生一次。您可以在应用程序启动期间触发此创建 - 应用程序只需要一些时间来启动和配置它们需要使用的所有基础设施。

编辑:

我必须在每个不适合这种情况的模块中引用 EntityFramework.dll。

是的。您希望允许其他开发人员定义他们自己的实体,这些实体将由您的核心应用程序持久化。在这种情况下,他们必须使用您选择的持久性框架来告诉您的应用程序如何持久化他们的实体。

==>正如我之前提到的,EF 不是我唯一的 DataProvider !我必须有一些其他的 DP,例如 DB4O 的数据提供者等,所以我不想引用每个提供者对每个模块的依赖项......因此我需要将 EF 封装在一个单独的程序集中

如果您使用存储库,每个模块甚至应该包含自己的存储库以使用其自己的实体 - 通用存储库不存在。通用存储库是多余的无用层,只会使您选择的 ORM 的工作更加困难。说清楚 - 存储库模式的正确实现不是通用的。它是特定的,它公开了单个实体或聚合根的数据访问功能。

==>我可以要求任何可靠的参考吗?!为什么我应该为每个模块添加一个存储库,以防只有一个存储库可以满足我的所有要求?哪个是多余的?在我看来,使用特定或通用代表在正确的情况下都是正确的。我的模块中有 90% 具有来自存储库的相同要求,并且它们都应该具有 CRUD ...

如果您不希望模块中的 EF 依赖,要么根本不使用 EF,要么定义您自己的中间映射层,该层将在您的应用程序中转换为特定映射 - 大量工作零附加值。

==>事实上,我正在尝试定义自己的映射层,因为我在我的应用程序架构中需要它。它对我来说不是没用的。这是我问如何实现它的唯一原因。我正在寻找最好的解决方案,我希望你能帮我解决它:)

其他选项就是不允许您的模块使用新实体,因为它看起来更像您当前的期望。如果模块开发人员必须为他的实体定义新的数据库表,他还必须能够使用持久性并定义表和他的实体之间的映射。

==>好主意,但不适合我的情况;)

我必须在启动时反映每个模块 dll,这意味着要反映很多沉重的 dll 并且......还有其他想法吗?

您是否在启动过程中见过 Photoshop、Visual Studio 甚至 MS Office 应用程序等应用程序?当您看到启动画面时,您认为发生了什么?应用程序正在初始化 - 它正在加载和初始化其功能和插件。即使是服务器应用程序也可能需要几分钟才能完全启动。您正在构建模块化应用程序(不是复合应用程序),因此您必须为该要求付费。

==>是的,我想我看到了其中一些!例如,如果他们在启动时加载所有托盘或侧边栏,他们必须雇用我。嘿亲爱的微软,如果您不知道什么是延迟加载,我可以帮助您提高性能 :)

如果您不想自己使用反射,可以使用 MEF 构建模块化基础架构。

==>我已经在使用 Prism 和 MEF 来处理模块化,但仅适用于模块,不适用于我的提供商......

听起来 EF 不是企业复合应用程序的好解决方案,对吧?

您没有提出任何不应由 EF 满足的企业要求。您只是与您的期望作斗争,以允许模块开发人员使用新实体,但不让他们能够描述这些实体将如何被持久化——但谁来描述呢?

==>一个模型或一个中间映射器层,如果 EF 支持,它将在每个模块加载和映射实体(据我所知不能)我需要像引导程序这样的东西来为每个提供者映射实体:)

您不是在构建复合应用程序。复合应用程序采用单独工作的现有功能(组件、现有应用程序)并将它们组合到一个新应用程序中。您正在构建模块化应用程序,您的核心可以托管其他模块,但如果没有您的托管基础​​设施,这些模块将无法运行。

==>我不打算就我的应用程序及其架构进行演讲,但我认为就这么多就足够了,你知道这是一个复合/模块化应用程序......

我应该切换到模型优先吗?!!

模型优先(通常是 EDMX)确实不适合您的期望,因为在模型优先的情况下,每个模块都需要自己的 EDMX 文件和自己的上下文。

==>但我可以在运行时更改 EDMX 文件的模型和 xml,对吗?!

您也不能首先通过代码使用自动数据库生成,因为任何新模块都会破坏您的应用程序或 EF 将删除您当前的数据库。

==>感谢这个建议,虽然我以前知道,但我当然会更加关注它。

4

1 回答 1

2

您可以要求每个模块必须包含它使用的每个新实体的映射类。当您启动应用程序时,您将只使用反射来获取所有派生自的类StructuralTypeConfiguration<>(包括实体和复杂类型),创建这些类型的实例并将它们添加到Configurations集合中DbModelBuilder(可以在 中完成OnModelCreating)。

这将需要一些时间,但它只会在第一次使用上下文时发生一次。您可以在应用程序启动期间触发此创建 - 应用程序只需要一些时间来启动和配置它们需要使用的所有基础设施。

编辑:

我必须在每个不适合这种情况的模块中引用 EntityFramework.dll。

是的。您希望允许其他开发人员定义他们自己的实体,这些实体将由您的核心应用程序持久化。在这种情况下,他们必须使用您选择的持久性框架来告诉您的应用程序如何持久化他们的实体。

如果您使用存储库,每个模块甚至应该包含自己的存储库以使用其自己的实体 - 通用存储库不存在。通用存储库是多余的无用层,只会使您选择的 ORM 的工作更加困难。说清楚 - 存储库模式的正确实现不是通用的。它是特定的,它公开了单个实体或聚合根的数据访问功能。

如果您不希望模块中的 EF 依赖,要么根本不使用 EF,要么定义您自己的中间映射层,该层将在您的应用程序中转换为特定映射 - 大量工作零附加值。

其他选项就是不允许您的模块使用新实体,因为它看起来更像您当前的期望。如果模块开发人员必须为他的实体定义新的数据库表,他还必须能够使用持久性并定义表和他的实体之间的映射。

我必须在启动时反映每个模块 dll,这意味着要反映很多沉重的 dll 并且......还有其他想法吗?

您是否在启动过程中见过 Photoshop、Visual Studio 甚至 MS Office 应用程序等应用程序?当您看到启动画面时,您认为发生了什么?应用程序正在初始化 - 它正在加载和初始化其功能和插件。即使是服务器应用程序也可能需要几分钟才能完全启动。您正在构建模块化应用程序(不是复合应用程序),因此您必须为该要求付费。

如果您不想自己使用反射,可以使用 MEF 构建模块化基础架构。

听起来 EF 不是企业复合应用程序的好解决方案,对吧?

您没有提出任何不应由 EF 满足的企业要求。您只是与您的期望作斗争,以允许模块开发人员使用新实体,但不让他们能够描述这些实体将如何被持久化——但谁来描述呢?

您不是在构建复合应用程序。复合应用程序采用单独工作的现有功能(组件、现有应用程序)并将它们组合到一个新应用程序中。您正在构建模块化应用程序,您的核心可以托管其他模块,但如果没有您的托管基础​​设施,这些模块将无法运行。

我应该切换到模型优先吗?!!

模型优先(通常是 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 会话将从该目录加载所有映射文件。

于 2012-02-05T10:20:26.097 回答