跨实体数据模型撰写查询

Abh*_*tel 11 entity-framework entity-framework-4

如果模型访问相同的底层数据库,是否有办法从2个不同的实体模型组成查询.

我的方案是:我有一个使用EF进行数据访问的框架.(EDM 1)我有一个客户端应用程序,它使用框架的服务,并使用EF进行自己的数据访问.(EDM2)

在某些情况下,我需要撰写查询并加入跨越2个EDM的实体.

有没有办法在没有从第一个EDM获取内存中的数据然后从第二个EDM的实体在内存中应用其他谓词/连接的情况下执行此操作?

我希望我能以正确的方式阐明这一点

编辑 @Ladislav Mrnka:第一个EDM是可重用框架的数据访问层.将来自此EDM的EF生成实体与消费客户端的实体耦合是没有意义的.如果我这样做,它会破坏API的可重用性并且我必须携带额外的膨胀(客户端的EF元数据和数据库表)每次我想重新部署框架.这也会使设计师在管理模型时变得笨拙.

我目前正在使用你提到的第7项作为解决方案而且性能很糟糕,因为我必须最终返回比使用EDM1的框架所需的更多数据(即实体),然后过滤掉不需要的数据基于基于第二EDM中的实体的属性值的谓词/条件.最终结果是性能下降和DBA不满意.

出于这个原因,我最终将检索实体所需的逻辑推送到SPROC,在该SPROC中,我可以访问EDM使用的表并应用所需的谓词,并使整个查询在DB中运行,而不是将数据存入内存然后过滤掉不必要的.Downside是我不能使用LINQ

你提到的第8项听起来很有意思,但听起来我怀疑你在设计时得到了强烈的打字,或者你呢?你可以在某个地方上传你的代码示例,以便我可以尝试一下吗?

Lad*_*nka 5

重要的编辑

有两种ObjectContext类型没有支持实现这一目标.您的查询必须始终针对单个执行ObjectContext.

可能是最好的方式:这对我自己来说很有趣.我从非常简单的想法开始.两个EDMX文件(与POCO T4生成器一起使用),每个文件包含单个实体.我从第二个连接字符串中获取元数据描述并将其添加到第一个连接字符串 我曾经ObjectContextObjectSet直接.通过这样做,我能够从单个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=&quot;Data Source=.;Initial Catalog=Test;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
</configuration>
Run Code Online (Sandbox Code Playgroud)

此连接字符串包含两个模型的元数据 - FirstModel.edmx和SecondModel.edmx.

另一个问题是强制EF使用这两个文件的映射.每个EDMX文件都必须为SSDL和CSDL定义唯一的容器.ObjectContext提供称为的财产DefaultContainerName.可以直接或通过某些构造函数重载来设置此属性.设置此属性后,将ObjectContext实例绑定到单个EDMX - 对于此方案,您不能设置此属性.省略DefaultContainerName可能会产生一些后果,因为某些功能和声明可能会停止工作(您将收到运行时错误).除非您想使用某些高级功能,否则您不应该遇到POCO问题.如果你使用Entity对象(重EF实体),你很可能会遇到问题.使用定义为字符串的实体集的所有方法都依赖于容器.因此我建议仅在必要时使用这样的配置 - 用于交叉模型查询.

最后一个问题是生成实体和"强类型"派生ObjectContext.要做的就是修改T4模板,以便一个模板从多个EDMX文件中读取数据并为所有这些文件生成上下文结束实体 - 我已经在我的项目中执行此操作并且它可以工作.默认T4实施不遵循前一段中描述的必要方法.源自ObjectContext默认T4实现取决于单个EDMX和实体容器.


这部分是在上一次编辑之前编写的.

我要留下其他信息只是因为其中一些信息在其他方案中非常有用,包括使用多个数据库.

ORM like entity framework在对象世界和数据库世界之间的映射之上运行.在EF中,对象世界由CSDL描述,数据库世界被描述为SSDL,它们之间的映射被描述为MSL(所有这些都只是具有众所周知的模式的XML).在设计时,这些描述是存储在EDMX文件中的模型的一部分.在编译期间,这些描述从EDMX中提取,默认情况下作为资源文件包含在已编译的程序集中.

当您创建ObjectContext它的实例时,会收到连接字符串,其中包含对CSDL,SSDL和MSL资源文件的引用.SSDL或MSL不指定include元素来添加来自其他文件的信息.CSDL提供了使用元素,允许您重用现有映射,但设计人员不支持此功能.ConnectionString用于初始化EntityConnection实例,该实例又用于初始化ObjectContext MetadataWorkspace(运行时映射信息).也ObjectContext没有提供将多个上下文嵌套到层次结构中的任何功能.连接字符串不能包含对这些文件的多个实例的引用. 编辑:它可以.我刚试过它.见初始段落.

当您在其实例上运行Linq或ESQL查询时,使用ObjectContextMSL将您的实体或POCO类(由CSDL定义)映射到数据库查询(由数据库表的SSDL描述定义).如果它没有这些信息,它将无法工作(如果它存储在单独的EDMX中,它就不能拥有该信息).

那么如何解决这个问题呢?有几种方法:

  1. 始终考虑:将映射合并到一个文件中(如果多个文件用于同一个数据库).这被认为是使用EF的方式,正如您所提到的,您正在查询相同的DB,因此不需要两个EF模型.
  2. 第二个模型中的重复实体描述.如果使用EF4和POCO,则可以将多个模型中的相同描述映射到一个POCO类定义中.我不喜欢这种解决方案,但有时它可以提供帮助.
  3. 定义包含查询(或查询核心)的数据库视图或存储过程,并将其在一个模型中映射到新实体.
  4. 在一个模型中使用DefiningQuery(如果使用"从数据库更新"功能,则可能需要第三个)并将其映射到新实体.DefiningQuery是在SSDL中定义的自定义SQL查询,而不是表或视图描述.
  5. 使用函数与自定义CommandText指定数据库查询.它类似于使用DefiningQuery,它具有相同的限制.您必须手动(在EDMX中)将函数的结果映射到新的复杂类型(与映射到新实体的DefiningQuery的另一个区别).
  6. 为查询结果定义新类型(类型的属性必须与查询中返回的列具有相同的名称)并使用ObjectContext的ExecuteStoreQuery(仅在EF4中).
  7. 将查询分为两部分,每部分在自己的上下文中单独执行,并使用linq-to-objects获取结果.我不喜欢这个解决方案.

  8. 这个只是高级别的想法 - 我没有尝试过,我不知道它是否有效.如上所述,运行时映射依赖于MetadataWorkspace填充的实例的内容EntityConnection.EntityConnection还提供了MetadataWorkspace直接接收实例的构造函数.因此,通常如果可以MetadataWorkspace从多个EDMX 填充,您将不需要多个ObjectContext实例,但您的映射仍将分为两个EDMX.这有望允许您在两个映射文件之上编写自定义Linq查询).编辑:应该可以,因为如果在连接字符串中定义多个映射,它正是EF正在做的事情.

  9. 使用CSDL使用功能将模型分解为多个重用零件.