Sql server code first实体框架能否在同一个框中使用SQL Server DBs进行跨数据库查询?

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*视图污染我们的数据库不是一个选项,而且

我知道有很多关于Entity Framework在发布到的同一服务器上执行跨数据库查询的问题。大多数情况下,答案似乎是“不”,而这个链接来自。然而,实体框架一直在变化,随着CTP5的退出,我想知道答案是否仍然是一样的——你不能这样做,或者你可以这样做,如果你手动编辑edmx文件,或者你必须使用视图。这一特性本身就是我仍然使用LINQtoSQL的原因,因为我们在同一台服务器上有多个SQLServer2008数据库,需要跨它们进行查询。用成百上千的
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