[英]Entity Framework and LINQ left join and include on same table
我的用戶具有以下類結構,以及它們所關聯的不同公司所具有的權限:
public class User
{
public Guid Id { get; set; }
public List<Permission> Permissions { get; set; }
public Company DefaultCompany { get; set; }
}
public class Permission
{
public User User { get; set; }
public Company Company { get; set; }
public int PermissionLevel { get; set; }
}
public class Company
{
public Guid Id { get; set; }
public string Name { get; set; }
}
這將產生三個SQL表。 Permission.User_Id> User.Id和Permission.Company_Id> Company.Id之間有一個FK。 User.DefaultCompany與Company表之間沒有明確的關系(即FK)。 這是有目的的,因為在我們的數據庫模式中有傳統的選擇。
我還有一個數據庫存儲庫方法,可以通過其ID來吸引用戶,並包括完整的公司記錄:
public User GetById(Guid Id)
{
return (from r in this.Context.Users.Include("Permissions.Company")
where r.Id == Id
select r)
.SingleOrDefault();
}
這可以正常工作,但是它沒有設置DefaultCompany
屬性。 因此,我嘗試通過將此方法更改為以下內容來進行設置。 值得指出的是,代表DefaultCompany的Company記錄與User共享相同的ID值。
public User GetById(Guid Id)
{
return (from r in this.Context.Users.Include("Permissions.Company")
where r.Id == Id
join c in this.Context.Companies on r.Id equals c.Id into companies
from company in companies.DefaultIfEmpty()
select new { User = r, Company = company })
.ToList()
.Select(p => { p.User.DefaultCompany = p.Company; return p.User; })
.SingleOrDefault();
}
實際上,這確實設置了DefaultCompany
但是它的副作用是沒有選擇“ Permissions
列表。 我可以通過兩個單獨的操作來完成所有這些操作,如以下代碼所示,但是如果不需要的話,我不想兩次訪問數據庫。
public User GetById(Guid Id)
{
var u = (from r in this.Context.Users.Include("Permissions.Company")
where r.Id == Id
select r)
.SingleOrDefault();
u.DefaultCompany = (from r in this.Context.Companies where r.Id == u.Id select r).SingleOrDefault();
return u;
}
還有另一種方法可以做到這一點嗎?
編輯:解釋結果SQL數據模型和其他示例。
有兩種可能的解決方案。
最干凈的方法是使用Fluent API來指示該模型,即用戶與公司之間存在1對1的關系。
重寫上下文的OnModelCreating(DbModelBuilder modelBuilder)
方法。
在其中配置如下的1 ro 1關系:
modelBuilder.Entity<User>()
.HasOptional(u => u.DefaultCompany)
.WithRequired();
注意:使用此配置時,有1個用戶與0個或1個默認公司的關系(請注意HasOptional
中的HasOptional
)。 並且默認公司必須在另一邊有一個用戶。 配置了1到1(或1到0..1)關系后,EF將自動使用相關表的PK在它們之間創建關系。 您可以使用其他Fluent API函數微調關系
之后,您可以使用Include()
包括DefaultCompany
:
User user = ctx.Users
.Include(u => u.DefaultCompany)
.SingleOrDefault(u => u.Id == userId);
另一個更丑陋的解決方案是使用第二個查詢,並將丟失的權限包括在投影中,以強制EF從數據庫中恢復它們。
// ...
select new { User = r, Company = company, Companies = r.Permissions }
// ...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.