Sql server code first实体框架能否在同一个框中使用SQL Server DBs进行跨数据库查询?
我知道有很多关于Entity Framework在发布到的同一服务器上执行跨数据库查询的问题。大多数情况下,答案似乎是“不”,而这个链接来自。然而,实体框架一直在变化,随着CTP5的退出,我想知道答案是否仍然是一样的——你不能这样做,或者你可以这样做,如果你手动编辑edmx文件,或者你必须使用视图。这一特性本身就是我仍然使用LINQtoSQL的原因,因为我们在同一台服务器上有多个SQLServer2008数据库,需要跨它们进行查询。用成百上千的Sql server code first实体框架能否在同一个框中使用SQL Server DBs进行跨数据库查询?,sql-server,entity-framework,ef-code-first,Sql Server,Entity Framework,Ef Code First,我知道有很多关于Entity Framework在发布到的同一服务器上执行跨数据库查询的问题。大多数情况下,答案似乎是“不”,而这个链接来自。然而,实体框架一直在变化,随着CTP5的退出,我想知道答案是否仍然是一样的——你不能这样做,或者你可以这样做,如果你手动编辑edmx文件,或者你必须使用视图。这一特性本身就是我仍然使用LINQtoSQL的原因,因为我们在同一台服务器上有多个SQLServer2008数据库,需要跨它们进行查询。用成百上千的select*视图污染我们的数据库不是一个选项,而且
select*
视图污染我们的数据库不是一个选项,而且在代码优先开发中,我没有edmx文件可编辑。我在玩酒吧数据库,看看能不能找到什么地方,但我被卡住了。有什么建议吗
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
namespace DbSchema {
public class Employee {
[Key]
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public short JobID { get; set; }
public Job Job { get; set; }
}
public class Job {
[Key]
public short ID { get; set; }
public string Description { get; set; }
}
public class PubsRepository : DbContext {
public DbSet<Employee> Employee { get; set; }
public DbSet<Job> Job { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
// employee
var eeMap = modelBuilder.Entity<Employee>();
eeMap.ToTable("employee", "dbo"); // <-- how do I reference another database?
eeMap.Property(e => e.ID).HasColumnName("emp_id");
eeMap.Property(e => e.FirstName).HasColumnName("fname");
eeMap.Property(e => e.LastName).HasColumnName("lname");
eeMap.Property(e => e.JobID).HasColumnName("job_id");
// job
var jobMap = modelBuilder.Entity<Job>();
jobMap.Property(j => j.ID).HasColumnName("job_id");
jobMap.Property(j => j.Description).HasColumnName("job_desc");
}
public List<Employee> GetManagers() {
var qry = this.Employee.Where(x => x.Job.Description.Contains("manager"));
Debug.WriteLine(qry.ToString());
return qry.ToList(); // <-- error here when referencing another database!
}
}
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
使用System.ComponentModel.DataAnnotations;
使用System.Data.Entity;
使用System.Data.Entity.ModelConfiguration;
命名空间DbSchema{
公营雇员{
[关键]
公共字符串ID{get;set;}
公共字符串名{get;set;}
公共字符串LastName{get;set;}
公共短作业ID{get;set;}
公共作业作业{get;set;}
}
公开课工作{
[关键]
公共短ID{get;set;}
公共字符串说明{get;set;}
}
公共类PubsRepository:DbContext{
公共数据库集雇员{get;set;}
公共数据库集作业{get;set;}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder){
//雇员
var eeMap=modelBuilder.Entity();
eeMap.ToTable(“employee”,“dbo”);//e.ID).HasColumnName(“emp_ID”);
属性(e=>e.FirstName).HasColumnName(“fname”);
属性(e=>e.LastName).HasColumnName(“lname”);
属性(e=>e.JobID).HasColumnName(“job_id”);
//工作
var jobMap=modelBuilder.Entity();
属性(j=>j.ID).HasColumnName(“job_ID”);
属性(j=>j.Description).HasColumnName(“作业描述”);
}
公共列表管理器(){
var qry=this.Employee.Where(x=>x.Job.Description.Contains(“经理”);
Debug.WriteLine(qry.ToString());
return qry.ToList();//我认为答案仍然是否定的,但还是有办法解决的
之所以为否,是因为EF使用DBContext,而context有一个连接字符串,并且连接字符串指向数据库
这里有两种解决方法:
- 对每个数据库使用两种不同的上下文,这意味着将数据带到客户端并在客户端上合并数据
- 在数据库上使用链接表,通过视图拉取数据,以便EF将其视为来自单个数据库
在您的代码中,看起来您正在使用2个DBContext,答案仍然是一样的。如果您想执行跨数据库查询,您必须返回SQL并在上下文中使用SqlQuery
。数据库有两种方法
当然,其中一种方法是在进行跨数据库查询的数据库中创建一个视图,然后像访问任何其他视图一样从模型中访问该视图
另一种方法是通过创建DefiningQuery
,在模型本身中创建相同的跨数据库查询视图。这与使用SQLClient的方式最为相似。在SQLClient中,您可以在T-SQL中创建视图作为SQLCommand的文本,然后执行命令来创建数据读取器或数据表。这里使用same T-SQL创建一个定义查询,然后将它与您手动创建的实体链接起来。这是一项有点工作量的工作,但它的功能正是您想要的
这里有一个关于使用定义查询的链接:
如果你碰巧有奥莱利的勒曼的书,第16章有一个很好的例子
因此,要直接使用SQLClient执行以前的操作,您必须跳过一些障碍,但您得到的是已建模的实体。警告!使用DefiningQuerys可能非常慢
下面是一个例子:
如果这是针对其创建实体的定义查询:
Select
C.CustomerID,
C.FirstName,
C.LastName,
G.SalesCatetory
From
CustomerDatabase.dbo.Customers C
Inner Join MarketingDatabase.dbo.CustomerCategories G on G.CustomerID = C.CustomerID
然后,当您根据CustomerID对实体进行选择时,SQL跟踪如下所示:
Select
[Extent1].[CustomerID] as [CustomerID],
[Extent1].[FirstName] as [FirstName],
[Extent1].[LastName] as [LastName],
[Extent1].[SalesCatetory] as [SalesCatetory]
From (
Select
C.CustomerID,
C.FirstName,
C.LastName,
G.SalesCatetory
From
CustomerDatabase.dbo.Customers C
Inner Join MarketingDatabase.dbo.CustomerCategories G on G.CustomerID = C.CustomerID
) as [Extent1]
Where '123456' = [Extent1].[CustomerID]
SQL Server运行此查询的速度可能非常慢。我有一个案例,比上面的示例稍微复杂一些,我在SQL Server管理控制台查询窗口中直接尝试了定义查询文本,为我要选择的值添加了where子句。它在不到一秒钟的时间内运行。然后,我通过选择t捕获了SQL跟踪他从为该定义查询创建的实体中获取了相同的值,并在SQL Server查询窗口中运行了SQL跟踪查询—耗时13秒
所以我想,进行跨数据库查询的唯一真正方法是在服务器上创建一个veiw。Ug。似乎让您只需执行eeMap.ToTable(“employee”,“MyOtherDB.dbo”)就很容易了
或其他什么。我们有太多跨数据库的表,这是不可行的。如果您关心事务之类的事情,那么使用多个DbContext从根本上来说是不可行的,而视图黑客对多个表来说是不可行的,在对象级别合并而不是让数据库执行这是性能自杀。哦,无论如何,谢谢。另一种选择(如果您使用的是SQLServer2005或更高版本)是同义词,但是您只能在代码中首先轻松地使用它们,不幸的是,设计器无法识别.edmx文件的同义词。如果您希望设计器支持这些同义词,我建议升级我的uservoice建议EF不支持,但NHibernate支持,而且没有黑客攻击。catalog