Может ли Entity Framework, использующая код, сначала выполнять кросс-запросы к базам данных SQL Server в одном блоке? - PullRequest
13 голосов
/ 15 марта 2011

Я знаю, что было много вопросов о том, как Entity Framework выполняет кросс-запросы к базам данных на одном и том же сервере, отправленном в stackoverflow . В основном ответ кажется «нет», и на эту ссылку с еще в 2008 году ссылается . Тем не менее, Entity Framework все время меняется и с CTP5, мне интересно, если ответ все тот же - что вы не можете сделать это, или вы можете сделать это, если вы вручную редактируете файл EDMX, или у вас есть использовать представления. Одна только эта функция - причина, по которой я все еще привязан к Linq-to-SQL, так как у нас есть несколько баз данных SQL Server 2008 на одном сервере, и нам необходимо выполнять запросы к ним. Загрязнение наших баз данных сотнями 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!
        }
    }
}

Ответы [ 4 ]

12 голосов
/ 15 марта 2011

Я думаю, что ответ все еще нет, но есть способы обойти это.

Причина, по которой это не так, в том, что EF использует DBContext, а контекст имеет строку подключения, а строка подключения отправляется в базу данных.

Вот два способа обойти это:

  • использовать 2 разных контекста, один для каждой базы данных, это будет означать передачу данных клиенту и объединение их на клиенте.
  • использовать связанные таблицы в базе данных, перетаскивая данные через представления, так что EF видит, что они поступают из одной базы данных.

В вашем коде похоже, что вы используете 2 dbcontexts

5 голосов
/ 12 апреля 2011

Есть два способа сделать это.

Одним из них является, конечно, создание представления в одной из баз данных, которое выполняет кросс-запрос базы данных, а затем доступ к представлению из вашей модели, как и в любом другом представлении.было ли это создать такое же представление запросов к нескольким базам данных внутри самой модели, создав DefiningQuery.Это наиболее похоже на то, как вы будете делать это с SQLClient.В SQLClient вы создадите представление в T-SQL как текст SQLCommand, а затем выполните команду для создания устройства чтения данных или таблицы данных.Здесь вы используете тот же T-SQL для создания DefiningQuery, а затем связываете его с сущностью, которую вы создаете вручную.Это немного работы, но она делает именно то, что вы хотите.

Вот ссылка на использование DefiningQuerys: http://msdn.microsoft.com/en-us/library/cc982038.aspx.

Если у вас есть книга " Программирование Entity Framework " Лермана из O 'Рейли, есть хороший пример в главе 16.

Так что вам нужно прыгнуть через несколько обручей, чтобы сделать то, что вы делали напрямую с SQLClient, НО вы получите смоделированный объект.

4 голосов
/ 13 апреля 2011

Внимание!использование 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

Тогда, когда вы делаетепри выборе Entity по 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 может выполнить этот запрос очень медленно.У меня был один случай, немного более сложный, чем в приведенном выше примере, где я попробовал текст DefiningQuery непосредственно в окне запроса консоли управления SQl Server, добавив предложение where для значения, для которого я хотел выбрать.Это работает менее чем за секунду.Затем я захватил трассировку SQL от выбора того же значения из сущности, созданной для этого DefiningQuery, и запустил запрос трассировки SQL в окне запроса SQL Server - это заняло 13 секунд!

Так что я думаю, что только реальный путьсделать кросс-запросы к базе данных - это создать вид на сервере.

4 голосов
/ 15 марта 2011

Ответ остается прежним.Если вы хотите выполнить кросс-запрос к базе данных, вы должны вернуться к SQL и использовать SqlQuery на context.Database.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...