[英]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 地址並檢查該人是否實際存在,是否更有效:
對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(); }
獲取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
方法的調用並傳遞導航屬性。 傳遞的實體將被急切地加載。 在查詢結束時,您可以使用任何會立即執行的方法,例如First
、 FirstOrDefault
、 Single
、 SingleOrDefault
、 ToList
等。 您不能將Include
與Find
一起使用,因為后者是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.