[英]Asynchronous queries and lazy loading in Entity Framework
我們正在將實體框架4.2與模型優先方法和DbContext代碼生成一起使用。
假設我們在實體框架中有以下數據模型:
class Person
{
public string Name { get; set; }
public Address Address { get; set; }
}
class Address
{
public string City; { get; set; }
}
該場景如下:
在階段3中,人員通過以下方式加載:
using (DatabaseContext context = new DatabaseContext())
{
Person person = from p in context.Persons.FirstOrDefault();
return person;
}
好的,我知道(理論上)我可以通過兩種方式強制加載Address對象:1)使用DbSet.Include,例如:
context.Persons.Include("Address").FirstOrDefault();
2)在數據庫上下文仍處於活動狀態時訪問Person.Address,因為這將強制加載地址
Person person = context.Persons.FirstOrDefault();
Address address = person.Address;
return person;
當然,第一個是首選的解決方案,因為它不如第二個那么丑陋(僅訪問該屬性以強制加載數據,然后丟棄結果是丑陋的)。 同樣,如果是一個集合(例如人員列表),我將不得不遍歷該集合並分別為每個人訪問該地址。 第一個解決方案的問題在於,只有DbSet具有Include方法,而從查詢返回的所有其他集合都沒有。 因此,假設我具有以下數據庫結構
class Resource {}
class Person : Resource { public Address Address { get; set; } }
class Appointment { public IList<Resource> Resources { get; set; } }
而且我想加載所有特定的約會,並在每個人的資源中包含地址,這給我帶來了麻煩(或者至少我沒有辦法為它編寫查詢)。 這是因為context.Appointments.Resources不是DbSet類型,而是一個沒有Include方法的ICollection。 (好吧,也許在這種情況下,我可以以某種方式從context.Persons而不是context.Appointments編寫查詢,這樣我可以使用Include,但是在許多情況下這是不可能的)
所以基本上問題是 :
您可以在應用程序或測試啟動時設置包含策略的實現。
首先定義一個擴展方法:包含,它定義實際的包含機制(默認情況下不執行任何操作)
/// <summary>
/// Extension methods specifically for include since this is essential for DomainContext but not part of IQueryable by default
/// </summary>
public static class QueryableIncludeExtensions
{
public static IIncluder Includer = new NullIncluder();
public static IQueryable<T> Include<T, TProperty>(this IQueryable<T> source, Expression<Func<T, TProperty>> path)
where T : class
{
return Includer.Include(source, path);
}
public interface IIncluder
{
IQueryable<T> Include<T, TProperty>(IQueryable<T> source, Expression<Func<T, TProperty>> path) where T : class;
}
internal class NullIncluder : IIncluder
{
public IQueryable<T> Include<T, TProperty>(IQueryable<T> source, Expression<Func<T, TProperty>> path)
where T : class
{
return source;
}
}
}
然后創建一個EF特定的includer實現,例如:
internal class DbIncluder : QueryableIncludeExtensions.IIncluder
{
public IQueryable<T> Include<T, TProperty>(IQueryable<T> source, Expression<Func<T, TProperty>> path)
where T : class
{
return DbExtensions.Include(source, path);
}
}
最后,將DbIncluder實現掛接到您需要的項目中,在我的情況下,我這樣做是:
public class DomainContext : DbContext, IDomainContext
{
static DomainContext()
{
// register the DbIncluder for making sure the right call to include is made (standard is null)
QueryableIncludeExtensions.Includer = new DbIncluder();
}
現在,IQueryable始終具有擴展方法:包含可用。 如果需要,可以將其擴展為IEnumerable。 實際的實現只需通過QueryableIncludeExtensions.Includer設置即可
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.