簡體   English   中英

我什么時候應該使用導航屬性來查詢數據庫?

[英]When should I use navigation properties to query the database?

在我的 Entity Framework 6 應用程序中,我有一張人們的 email 地址表:

public class EmailAddress
{
    public int Id { get; set; }

    public int PersonId { get; set; }

    public string EmailAddress { get; set; }

    public virtual Person Person { get; set; }
}

並且Person object 還引用了這些 email 地址:

public class Person
{
    public int Id { get; set; }
    {...}

    public virtual ICollection<EmailAddress> EmailAddresses { get; set; }
}

如果我想獲取一個人的所有 email 地址檢查該人是否實際存在,是否更有效:

  1. Persons表運行Any()查詢,然后對EmailAddresses表運行另一個查詢,使用PersonId作為參數:

     public IEnumerable<EmailAddress> GetAddressesByPerson(int personId) { if (.Context.Persons.Any(x => x;Id == personId)) { throw new Exception("Person not found"). } return Context.EmailAddresses.Where(x => x.PersonId == personId);ToList(); }
  2. 獲取Person object 並返回EmailAddresses導航屬性:

     public IEnumerable<EmailAddress> GetAddressesByPerson(int personId) { var person = Context.Persons.Find(personId); if (person == null) { throw new Exception("Person not found") } return person.EmailAddress; }

在第一種解決方案的情況下,EF 將生成包含EXISTS語句的 sql 查詢。 然后,如果它退出,您將對數據庫執行完全不同的第二次查詢。

在第二種解決方案的情況下,您將只發送select... from Persons where.. 並且當您將EmailAddress設置為導航屬性時,如果啟用Lazy Loading ,則 EF 將基於personId生成並執行對EmailAdress表的查詢。 如果未啟用Lazy Loading ,則EmailAddress將為 null 或為空。

作為第三個選項,您使用Eager Loading功能,這將使 EF 生成join查詢,並將在一個 go 中感染person和相關的EmailAddress es。

因此,如果大多數情況下您希望擁有正確的personId ,那么您可以切換到Eager Loading模式。 當您僅在某些情況下需要獲取相關實體時, Lazy Loading在場景中非常有用。

順便說一句,我建議您打開登錄 EF以查看生成的查詢。

因此,這里是急切加載相關實體的代碼示例:

var person = Context.Persons
            .Include(s ⇒ s.EmailAddresses)
            .FirstOrDefault(x => x.Id == personId);

關鍵是添加對Include方法的調用並傳遞導航屬性。 傳遞的實體將被急切地加載。 在查詢結束時,您可以使用任何會立即執行的方法,例如FirstFirstOrDefaultSingleSingleOrDefaultToList等。 您不能將IncludeFind一起使用,因為后者是DbSet的方法。 在您的情況下,最相關的是Single ,如果表中沒有具有指定 ID 的人,它將自動拋出異常。

一個選項:

public IEnumerable<EmailAddress> GetAddressesByPerson(int personId)
{
    var queryResults = Context.Persons
        .Where(x => x.Id == personId)
        .Select(x => new { EmailAddresses = x.EmailAddresses })
        .Single(); 

    return queryResults.EmailAddresses;
}

上面的查詢斷言應該返回單個 Person 的電子郵件地址。 您可以執行SingleOrDefault然后檢查結果是否為 #null 以自定義錯誤消息,盡管我傾向於保持異常消息的純凈。 然后我們返回選定的集合。 因此,如果一個人存在,但沒有電子郵件地址,您將收到一個空列表。 如果此人不存在,您將獲得 Expected 1, found 0 異常。 如果該 ID 存在多個人(不應該,但是...),您將得到一個預期的 1,發現多個異常。 不要使用FirstOrDefault ,除非您預計可能有多個,並提供OrderBy以確保數據順序是可預測的。

暫無
暫無

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

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