2013-12-10 5 views
7

Я поддерживаю API, который на основе запроса списка людей возвращает другой набор результатов, основанный на запросе. Например, некоторые клиенты API хотят получить список людей и список их взаимодействий, другие хотят людей и список своих метаданных. Все это можно указать в запросе метода API, который возвращает людей.Entity Framework - условно включать связанные объекты

Это не появляется на работу:

using (var dbcontext = new ExampleEntities()) 
{ 
    var query = dbcontext.People.AsQueryable(); 
    //determined in earlier application logic based on request 
    if(includeMetadata) 
    { 
     query = query.Include("metadata"); 
    } 
    //determined in earlier application logic based on request 
    if(includeInteractions) 
    { 
     query = query.Include("interactions"); 
    } 
    /* ...SNIP... */ 
} 

То, что я не хочу, чтобы сделать это:

var query = dbcontext.People.Include("Metadata").Include("interactions"); 

, который будет означать, каждый запрос, чтобы получить человек, будет включать в себя все связанные с ними объектов, даже если запрашивающий клиент API им не нужен.

Я также не хочу, чтобы закодировать все возможные комбинации логики:

if(includeMetadata && includeInteractions) 
{ 
    var query = dbcontext.People.Include("Metadata").Include("interactions"); 

} 
else if(includeMetadata) 
{ 
    var query = dbcontext.People.Include("Metadata"); 
} 
else if(includeInteractions) 
{ 
    var query = dbcontext.People.Include("Interactions"); 
} 
else 
{ 
    var query = dbcontext.People; 
} 

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

ответ

10

возможность увязывать IQueryable-х

using (var dbcontext = new ExampleEntities()) 
{ 
    var query = dbcontext.People.AsQueryable(); 
    if(includeMetadata) 
    { 
     query = query.Include("metadata"); 
    } 
    if(includeInteractions) 
    { 
     query = query.Include("interactions"); 
    }  
} 
+1

Возможно ли это только в другой версии Entity Framework? я получаю следующее сообщение об ошибке: Ошибка \t \t 37 «System.Linq.IQueryable » не содержит определение для «Включить» и не метод расширения «не включать» принятие первого аргумента типа «System.Linq.IQueryable '(вы не указали директиву по использованию или ссылку на сборку?) Возможно, отсутствует сборка расширений? –

+1

Цепочки - это стандартная функция LINQ. Но 'Include' - это метод расширения EF (http://msdn.microsoft.com/en-us/library/gg696450%28v=vs.103%29.aspx) и требует ссылки на сборку EntityFramework.dll и добавление' используя System.Data.Entity; 'также удалите это' AsQueryable() '. – VahidN

+0

Хорошо. Я был смущен, так как мог позвонить. Включить в dbcontext.SomeTable, но не someQuery. После того, как я добавил необходимый импорт, он работал нормально. Я уже исправлял EntityFramework.dll –

0

Ваш первый пример должен работать, если заменить u с query

u = u.Include("metadata"); 

с

query = query.Include("metadata"); 
+0

опечатка - извините! Опечатка существовала только в вопросе –

0

Работает хорошо здесь ... проверив sql с обработчиком журнала EF 6

[TestClass] 
public void SomeTestClass 
{ 
    [TestMethod] 
    public void ShouldLoadOnlyRequiredCollections() 
    { 
     Database.SetInitializer(new DropCreateDatabaseAlways<HomesContext>()); 

     var db = new HomesContext(); 

     Assert.IsFalse(db.Homes.Any()); 

     var home = db.Homes.Create(); 

     db.Homes.Add(home); 

     home.Staff.Add(new Staff { Name = "wilma" }); 
     home.Staff.Add(new Staff { Name = "betty" }); 

     home.Residents.Add(new Resident { Name = "fred" }); 
     home.Residents.Add(new Resident { Name = "barney" }); 

     db.SaveChanges(); 

     db = null; 

     Database.SetInitializer(new DropCreateDatabaseIfModelChanges<HomesContext>()); 

     var sb = new StringBuilder(); 
     db = new HomesContext(); 

     db.Database.Log = ((s) => { sb.Append(s + "\r"); }); 

     Assert.IsTrue(db.Homes.Any()); 

     string log; 

     log = sb.ToString(); 

     Assert.IsTrue(sb.ToString().Contains("FROM [dbo].[Homes]")); 

     sb = new StringBuilder(); //ok get residents 

     var q = db.Homes.Include("Residents"); 

     Assert.IsTrue(string.IsNullOrEmpty(sb.ToString())); 

     var lst = q.ToList(); 

     log = sb.ToString(); 

     Assert.IsTrue(sb.ToString().Contains("[dbo].[Homes]")); 
     Assert.IsTrue(sb.ToString().Contains("[dbo].[Residents]")); 
     Assert.IsTrue(!sb.ToString().Contains("[dbo].[Staff]")); 

     sb = new StringBuilder(); //get staff 

     q = db.Homes.Include("Staff"); 

     Assert.IsTrue(string.IsNullOrEmpty(sb.ToString())); 

     lst = q.ToList(); 

     log = sb.ToString(); 

     Assert.IsTrue(log.Contains("[dbo].[Homes]")); 
     Assert.IsTrue(!log.Contains("[dbo].[Residents]")); 
     Assert.IsTrue(log.Contains("[dbo].[Staffs")); 



     sb = new StringBuilder(); //get residents and staff 

     q = db.Homes.Include("Staff"); 

     q = q.Include("Residents"); 

     lst = q.ToList(); 

     log = sb.ToString(); 

     Assert.IsTrue(log.Contains("[dbo].[Homes]")); 
     Assert.IsTrue(log.Contains("[dbo].[Residents]")); 
     Assert.IsTrue(log.Contains("[dbo].[Staffs]")); 




    } 
} 

public class HomesContext:DbContext 
{ 
    public DbSet<Home> Homes { get; set; } 
} 

public class Home 
{ 
    public Home() 
    { 
     Staff = new List<Staff>(); 
     Residents = new List<Resident>(); 
    } 
    public int HomeId { get; set; } 
    public string HomeName { get; set; } 

    public int MaxResidents { get; set; } 
    public int MaxStaff { get; set; } 

    public int CurrentResidents { get; set; } 

    [NotMapped] 
    public int CurrentStaff { get; set; } 

    public IList<Staff> Staff { get; set; } 
    public IList<Resident> Residents { get; set; } 
} 

public class Staff 
{ 
    public int StaffId { get; set; } 
    public string Name { get; set; } 
    public int HomeId { get; set; } 
    public Home Home { get; set; } 
} 

public class Resident 
{ 
    public int ResidentId { get; set; } 
    public string Name { get; set; } 

    public int HomeId { get; set; } 
    public Home Home { get; set; } 
} 
+0

Не уверен, что вы подразумеваете под этим. Как я могу проверить. Это снимает взгляд. –

+0

Я проверю версию EntityFramework и попробую обновить ее, если необходимо –

+0

Вы можете сделать 'msg = q.ToString()', и это даст вам SQL, который будет пытаться выполнить запрос, или вы можете запустить Sql Profiler , Но EF 6 хорош .. – ajd

Смежные вопросы