簡體   English   中英

使用泛型的實體框架相關對象

[英]Entity Framework related objects using generics

在對實體使用Linq時,有關將Include()和Load()用於相關表信息存在很多問題。 我對這個問題有不同的看法。

我的情況:

我有一個表,該表為系統中的每個用戶保存許多時間記錄,並且我使用存儲庫模式和泛型進行開發,因此我的所有實體都有一個接口,可用於標准方法調用。 我已關閉了延遲加載,並且自己加載了所有數據。 因此,存儲庫中用於從具有相關表的表中加載所有記錄的代碼如下:

public class Repository<T> : IRepository<T> where T : class
{
    protected readonly ApplicationDbContext Context;

    public Repository(IConnectionHelper connection)
    {
        Context = connection.Context;
    }
    public virtual DbSet<T> ObjectSet
    {
        get { return Context.Set<T>(); }
    }  
    public List<T> GetAll(String[] include, Expression<Func<T, bool>> predicate)
    {
        DbQuery<T> outQuery = null;
        foreach (String s in include)
        {
            outQuery = ObjectSet.Include(s);
            outQuery.Load();
        }
        return outQuery.Where(predicate).ToList();
    }
}

該方法的調用如下:

string[] includes = { "User.UserProfile", "CampaignTimeClocks.CampaignRole.Campaign", "Site", "Type" };
DateTime uTcCurrent = GetUtc();
DateTime MinClockinDate = uTcCurrent.AddHours(-10);
List<TimeClock> tcPending = _timeClock.GetAll(includes, x => (x.PendingReview || x.ClockInDate < MinClockinDate && x.ClockOutDate == null) && (x.Site.Id == currentUser.SiteId));

當此方法運行並加載第一個User.Profile表時,它將加載所有時間記錄並將其與所有用戶相關聯,這需要一分鍾以上的時間,這太長了,因為最終記錄數僅185條記錄,但查詢的初始負載正在運行27,000 * 560用戶,即1500萬條記錄,並且隨着時間的推移,這種情況只會變得更糟。

問題是如何在沒有這種負載開銷的情況下如何做到這一點,我知道我可以鏈接包含,但是由於包含的數量將根據所調用的數據的類型和用途而改變,因此我不能簡單地對a進行硬編碼包含鏈。

我也嘗試過:

List<TimeClock> testLst =  _timeClock.GetAll(x => x.PendingReview || 
     (x.ClockInDate < MinClockinDate && x.ClockOutDate == null))
          .Select(x => new TimeClock{Id = x.Id,
                                     ClockInDate = x.ClockInDate, 
                                     ClockOutDate = x.ClockOutDate,
                                     TotalClockTime = x.TotalClockTime,
                                     Notes = x.Notes, 
                                     PendingReview = x.PendingReview, 
                                     Type = x.Type,
                                     User = x.User, 
                                     CampaignTimeClocks = x.CampaignTimeClocks,
                                     TimeClockAdjustments = x.TimeClockAdjustments,
                                     Site = x.User.Site}).ToList();

這將為我提供User.Profile信息,但Site和Type屬性為null。

因此,我對如何在此處加載所需的數據感到迷茫。

非常感謝所有幫助。

你能先得到初始清單嗎

List<TimeClock> testLst =  _timeClock.Where(x => x.PendingReview || (x.ClockInDate < MinClockinDate && x.ClockOutDate == null)).ToList();

然后調用以T作為參數的修改后的GetAll()

您所做的每個include最終都會在db中執行聯接。 假設您的左表的記錄大小非常大,為1024個字節,並且您有許多詳細信息,例如1000,並且詳細記錄的大小僅為100。這將導致左表的信息重復1000次,該信息db將被連接起來,EF必須過濾掉重復的副本以創建您的左實例。

最好不使用include並進行顯式加載。 基本上在相同的上下文中執行2個查詢。

我有一個這樣的例子,與您的例子不同,但我希望您能理解。 它可能比依賴include快多達10倍。 (數據庫只能有效地處理有限數量的聯接)

var adressen = adresRepository
                .Query(r => r.RelatieId == relatieId)
                .Include(i => i.AdresType)
                .Select().ToList();

var adresids = (from a in adressen select a.AdresId).ToList();
            IRepositoryAsync<Comm> commRepository = unitOfWork.RepositoryAsync<Comm>();

            var comms = commRepository
                .Query(c => adresids.Contains(c.AdresId))
                .Include(i => i.CommType)
                .Select();

對於我使用include的commType和adresType,因為存在1對1的關系,我避免了太多的聯接,因此我的多個查詢將比使用include的單個查詢更快。 我沒有在第一個查詢中包括Comms來嘗試避免第二個查詢,關鍵是在這種情況下,兩個查詢比單個查詢要快。

請注意,我的代碼是使用我自己的存儲庫構建的,因此該代碼對您不起作用,但是您可以從中得到啟發。

我發現不使用Load()語句即可更有效地執行此操作的方法是將DBQuery更改為IQueryable並鏈接包含,返回執行的查詢結果,以及一起刪除DBQuery.Load()。 這將查詢的執行時間從秒更改為毫秒。

    public List<T> GetAll(String[] include)
    {
        IQueryable<T> outQuery = ObjectSet;
        foreach (String s in include)
        {
            outQuery = outQuery.Include(s);
        }
        return outQuery.ToList();
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM