代码优先实体框架可以在同一个机器上使用 SQL Server DB 进行跨数据库查询吗?

发布于 2024-10-23 15:46:53 字数 2477 浏览 1 评论 0原文

我知道有很多关于实体框架在同一服务器上进行跨数据库查询的问题发布到 stackoverflow。大多数情况下答案似乎是“否”,此链接来自 早在 2008 年就被引用了。然而,实体框架一直在变化,随着 CTP5 的出现,我想知道答案是否仍然相同 - 你不能这样做,或者如果你手动编辑 edmx 文件,或者你有使用视图。仅此功能就是我仍然依赖 Linq-to-SQL 的原因,因为我们在同一服务器上有多个 SQL Server 2008 数据库,并且需要跨它们进行查询。用数百个 select * 视图污染我们的数据库是不可行的,并且通过代码优先开发,我没有要编辑的 edmx 文件。我正在研究 pubs 数据库,看看是否可以到达某个地方,但我被困住了。有什么建议吗?

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!
        }
    }
}

I know there have been a lot of questions about Entity Framework doing cross database queries on the same server posted to stackoverflow. Mostly the answer seems to be 'no', and this link from way back in 2008 is referenced. However, Entity Framework is changing all the time and with CTP5 out, I'm wondering if the answer is still the same - that you can't do it, or you can do it if you manually edit the edmx file, or you have to use views. This feature alone is the reason I'm still tied to Linq-to-SQL, as we have multiple SQL Server 2008 databases on the same server and need to query across them. Polluting our databases with hundreds of select * views is not an option, and with code-first development I don't have an edmx file to edit. I was playing with the pubs database to see if I could get somewhere, but I'm stuck. Any suggestions?

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!
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

欢你一世 2024-10-30 15:46:53

我认为答案仍然是否定的,但有一些方法可以解决这个问题。

之所以没有,是因为EF使用了DBContext,而上下文有一个连接字符串,而连接字符串又连接到数据库。

这里有两种解决方法:

  • 对每个数据库使用两种不同的上下文,这意味着将数据带到客户端并在客户端上合并它。
  • 在数据库上使用链接表,通过视图提取数据,以便 EF 将其视为来自单个数据库。

在您的代码中,您似乎正在使用 2 个 dbcontext

I think that the answer is still no, but there are ways around it.

The reason why it is no, it that EF uses a DBContext, and a context has a connection string, and a connection string goes to a database.

Here are 2 ways around it:

  • use 2 different contexts one against each database, this will mean bringing data to the client and merging it on the client.
  • use linked tables on the database, pulling data through views, so that EF sees it as coming from a single database.

In your code it looks like you are using 2 dbcontexts

浊酒尽余欢 2024-10-30 15:46:53

有两种方法可以做到这一点。

当然,一种是在执行跨数据库查询的数据库之一中创建一个视图,然后像访问任何其他视图一样从模型访问该视图。

另一个是通过创建 DefiningQuery 在模型本身内创建相同的跨数据库查询视图。这与使用 SQLClient 执行此操作的方式最相似。在 SQLClient 中,您可以在 T-SQL 中创建视图作为 SQLCommand 的文本,然后执行该命令来创建数据读取器或数据表。在这里,您使用相同的 T-SQL 创建 DefiningQuery,然后将其与您手动创建的实体链接起来。这需要一些工作,但它完全符合您的要求。

以下是使用 DefiningQuerys 的链接:http:// msdn.microsoft.com/en-us/library/cc982038.aspx

如果您碰巧有 O 的 Lerman 的书“编程实体框架” “Reilly,第 16 章中有一个很好的例子。

因此,您必须跳过一些步骤才能完成以前直接使用 SQLClient 执行的操作,但您得到了建模的实体。

There are two ways to do it.

One is, of course, to create a view in one of the databases which does the cross database query, then access the veiw from your model as you would any other view.

The other was it to create the same cross database query view within the model itself by creating a DefiningQuery. This is most similar to how you would do it with SQLClient. In SQLClient, you'd create the view in T-SQL as the text of a SQLCommand, then execute the command to create a data reader or data table. Here you use the same T-SQL to create a DefiningQuery, then link it up with an Entity that you create manually. It's a bit of work, but it does exactly what you'd want it to.

Here's a link on using DefiningQuerys: http://msdn.microsoft.com/en-us/library/cc982038.aspx.

If you happen to have the book "Programming Entity Framework" by Lerman from O'Reilly, there a good example in chapter 16.

So you have to jump through a few hoops to do what you used to do directly with SQLClient, BUT you get the modeled Entity.

ぃ双果 2024-10-30 15:46:53

答案还是一样。如果您想执行跨数据库查询,则必须退回到 SQL 并在 context.Database 上使用 SqlQuery

The answer is still the same. If you want to execute cross database query you have to fall back to SQL and use SqlQuery on context.Database.

﹎☆浅夏丿初晴 2024-10-30 15:46:53

警告!使用 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 可能会非常缓慢地运行此查询。我有一种情况,比上面的示例稍微复杂一些,我通过为我想要选择的值添加一个 where 子句,直接在 SQl Server 管理控制台查询窗口中尝试 DefiningQuery 文本。它运行时间不到一秒钟。然后,我从为此 DefiningQuery 创建的实体中选择相同的值来捕获 SQL 跟踪,并在 SQL Server 查询窗口中运行 SQL 跟踪查询 - 花了 13 秒!

所以我想进行跨数据库查询的唯一真正方法是在服务器上创建一个视图。

Warning! using DefiningQuerys can be VERY SLOW!

Here's an example:

If this is the defining query that you create an Entity against:

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

Then when you do a select against the Entity by CustomerID, the SQL trace looks something like this:

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 may run this query very slowly. I had one case, a little more complicated than the above example, where I tried the DefiningQuery text directly in a SQl Server Management Console query window by adding a where clause for the value I wanted to select for. It run in less than a second. Then I captured the SQL Trace from selecting for the same value from the Entity created for this DefiningQuery and ran the SQL Trace query in a SQL Server query window - it took 13 seconds!

So I guess that only real way to do cross database queries is to create a veiw on the server.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文