Может ли первая кодовая структура Entity Framework выполнять кросс-запросы базы данных с базами данных SQL Server в одном окне?
Я знаю, что было много вопросов о Entity Framework, выполняющих кросс-запросы к базе данных на том же сервере, что и в qaru.site/info/396200/.... В основном ответ кажется "нет", и эта ссылка из возвращается в 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!
}
}
}
Ответы
Ответ 1
Я думаю, что ответа по-прежнему нет, но есть способы обойти его.
Причина, по которой это не так, заключается в том, что EF использует DBC-контекст, а контекст имеет строку подключения, а строка подключения - в базу данных.
Вот два способа обойти это:
- используйте два разных контекста по одному для каждой базы данных, это будет означать перенос данных клиенту и объединение его на клиенте.
- использовать связанные таблицы в базе данных, вытягивая данные через представления, так что EF видит, что он поступает из одной базы данных.
В вашем коде похоже, что вы используете 2 dbcontexts
Ответ 2
Есть два способа сделать это.
Один из них, конечно, должен создать представление в одной из баз данных, которая выполняет запрос кросс-базы данных, а затем получить доступ к вейлу из вашей модели, как и любое другое представление.
Другим было создание одного и того же представления запросов кросс-базы в самой модели, создав DefiningQuery
. Это наиболее похоже на то, как вы это сделаете с помощью SQLClient. В SQLClient вы должны создать представление в T-SQL как текст SQLCommand, а затем выполнить команду для создания считывателя данных или таблицы данных. Здесь вы используете один и тот же T-SQL для создания DefiningQuery, а затем связываете его с Entity, созданным вручную. Это небольшая работа, но она делает именно то, что вы хотите.
Здесь ссылка на использование DefiningQuerys
: http://msdn.microsoft.com/en-us/library/cc982038.aspx.
Если у вас есть книга "" Программирование сущности" Лермана из O'Reilly, там хороший пример в главе 16.
Итак, вам нужно перепрыгнуть через несколько обручей, чтобы делать то, что вы делали непосредственно с SQLClient, НО вы получаете смоделированную Entity.
Ответ 3
Ответ все тот же. Если вы хотите выполнить запрос кросс-базы данных, вы должны вернуться к SQL и использовать SqlQuery
в context.Database
.
Ответ 4
Внимание! использование DefiningQuerys может быть ОЧЕНЬ МЕДЛЕННО!
Вот пример:
Если это определяющий запрос, создающий объект Entity:
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 Trace для выбора для того же значения из Entity, созданного для этого DefiningQuery, и запускал запрос SQL Trace в окне запроса SQL Server - это заняло 13 секунд!
Итак, я предполагаю, что только реальный способ выполнения кросс-запросов базы данных - создать вейв на сервере.