重要修改
没有内置支持使用两个ObjectContext 类型实现此目的。您的查询必须始终针对单个 ObjectContext 执行。
可能是最好的方法:这对我来说很有趣,我自己尝试了一下。我从一个非常简单的想法开始。两个 EDMX 文件(与 POCO T4 生成器一起使用),每个文件都包含一个实体。我从第二个连接字符串中获取元数据描述并将其添加到第一个连接字符串中。我直接使用了ObjectContext 和ObjectSet。通过这样做,我能够从单个 ObjectContext 实例查询和修改这两个实体。我还尝试从这两个模型创建查询连接实体并且它有效。
这显然只有在两个 EDMX 都映射到同一个数据库(相同的数据库连接字符串)时才有效。
重要的部分是连接字符串:
<configuration>
<connectionStrings>
<add name="TestEntities" connectionString="metadata=res://*/FirstModel.csdl|res://*/FirstModel.ssdl|res://*/FirstModel.msl|res://*/SecondModel.csdl|res://*/SecondModel.ssdl|res://*/SecondModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.;Initial Catalog=Test;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
此连接字符串包含来自两个模型的元数据 - FirstModel.edmx 和 SecondModel.edmx。
另一个问题是强制 EF 使用这两个文件的映射。每个 EDMX 文件必须为 SSDL 和 CSDL 定义唯一的容器。 ObjectContext 提供名为 DefaultContainerName 的属性。该属性可以直接设置,也可以通过一些构造函数重载来设置。设置此属性后,您将 ObjectContext 实例绑定到单个 EDMX - 对于这种情况您不得设置此属性。省略 DefaultContainerName 可能会产生一些后果,因为某些功能和声明可能会停止工作(您会遇到运行时错误)。除非您想使用一些高级功能,否则您应该不会遇到 POCO 问题。如果您使用实体对象(重型 EF 实体),您很可能会遇到问题。使用定义为字符串的实体集的所有方法都依赖于容器。因此,我建议仅在必要时使用此类配置 - 用于跨模型查询。
最后一个问题是生成实体和“强类型”派生的ObjectContext。可行的方法是修改 T4 模板,以便一个模板从多个 EDMX 文件中读取数据并为所有这些文件生成上下文结束实体——我已经在我的项目中这样做了,它可以工作。默认 T4 实现不遵循上一段中描述的所需方法。从默认 T4 实现派生的 ObjectContext 依赖于单个 EDMX 和实体容器。
这部分是在上次编辑之前编写的。
我将留下其余信息,只是因为其中一些信息在其他场景中可能有用,包括使用多个数据库。
类似 ORM 的实体框架在对象世界和数据库世界之间的映射之上运行。在 EF 中,对象世界由CSDL 描述,数据库世界被描述为SSDL,它们之间的映射被描述为MSL(都只是具有众所周知的模式的XML)。在设计时,这些描述是存储在 EDMX 文件中的模型的一部分。在编译期间,这些描述是从 EDMX 中提取的,默认情况下作为资源文件包含在已编译的程序集中。
当您创建ObjectContext 的实例时,它会收到包含对 CSDL、SSDL 和 MSL 资源文件的引用的连接字符串。 SSDL 或 MSL 不指定包含元素以添加来自其他文件的信息。 CSDL 提供Using 元素,允许您重用现有映射,但设计器不支持此功能。 ConnectionString 用于初始化EntityConnection 实例,该实例又用于初始化ObjectContext 的MetadataWorkspace(运行时映射信息)。 ObjectContext 也不提供任何将多个上下文嵌套到层次结构中的功能。 连接字符串不能包含对这些文件的多个实例的引用。 编辑:它可以。我刚刚测试了它。请参阅开头的段落。
当您在ObjectContext 的实例上运行 Linq 或 ESQL 查询时,它使用 MSL 将您的实体或 POCO 类(由 CSDL 定义)映射到 DB 查询(由数据库表的 SSDL 描述定义)。如果没有此信息,它将无法工作(如果存储在单独的 EDMX 中,则无法获得该信息)。
那么如何解决这个问题呢?有几种方法:
-
始终考虑:将您的映射合并到一个文件中(如果多个文件用于同一个数据库)。这应该是使用 EF 的方式,正如您所提到的,您正在查询同一个数据库,因此不需要两个 EF 模型。
- 第二个模型中的重复实体描述。如果您使用 EF4 和 POCO,您可以将来自多个模型的相同描述映射到一个 POCO 类定义中。我不喜欢这个解决方案,但有时它会有所帮助。
- 定义包含查询(或查询核心)的数据库视图或存储过程,并将其在一个模型中映射到新实体。
- 在一个模型中使用DefiningQuery(如果您使用从数据库更新功能,您可能需要第三个)并将其映射到新实体。 DefiningQuery 是在 SSDL 中定义的自定义 SQL 查询,而不是表或视图描述。
- 使用Function 与自定义CommandText 指定数据库查询。它类似于使用 DefiningQuery 并且具有相同的限制。您必须手动(在 EDMX 中)将函数的结果映射到新的复杂类型(与映射到新实体的 DefiningQuery 的另一个区别)。
- 为查询结果定义新类型(该类型的属性必须与查询中返回的列同名)并使用 ObjectContext 的ExecuteStoreQuery(仅在 EF4 中)。
将查询分成两部分,每部分在自己的上下文中单独执行,并使用 linq-to-objects 获取结果。我不喜欢这个解决方案。
这只是一个高级想法 - 我没有尝试过,我不知道它是否有效。 如上所述,运行时映射取决于 @987654346 的内容从EntityConnection 填充的@ 实例。 EntityConnection 还提供了直接接收MetadataWorkspace 实例的构造函数。因此,一般来说,如果可以从多个 EDMX 填充 MetadataWorkspace,您将不需要多个 ObjectContext 实例,但您的映射仍将分为两个 EDMX。这有望让您在两个映射文件之上编写自定义 Linq 查询)。 编辑:这应该是可能的,因为如果您在连接字符串中定义多个映射,这正是 EF 正在做的事情。
使用CSDL Using feature 将模型分解为多个重复使用的部分。