[英]Query table including selfreference childs
抱歉標題含糊不清,我不知道如何正確解析它。
我必須有 2 個表, Uses
和Applications
一對多,Users 引用自身。 用戶可以是Dealer
或Manager
,1 個經銷商有多個經理。 目前我可以通過UserID
獲取所有應用程序,但如果用戶是Dealer
我無法弄清楚如何包含孩子。 我的意思是,如果用戶是Manager
則獲取他的應用程序,但如果是Dealer
獲取他的應用程序,包括他的孩子的應用程序。 編輯:
RoleID=1 // Dealer
RoleID=2 // Manager
這是我的模型
public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserID { get; set; }
[Column(TypeName = "varchar(50)")]
public string UserName { get; set; }
[Column(TypeName = "varchar(50)")]
public string Password { get; set; }
[Column(TypeName = "varchar(50)")]
public string DealerName { get; set; }
[Column(TypeName = "varchar(150)")]
public string Email { get; set; }
[Column(TypeName = "varchar(20)")]
public string PhoneNumber1 { get; set; }
[Column(TypeName = "varchar(20)")]
public string PhoneNumber2 { get; set; }
[Column(TypeName = "varchar(100)")]
public string PhysicalAddress { get; set; }
[Column(TypeName = "varchar(100)")]
public string PostalAddress { get; set; }
[Column(TypeName = "varchar(50)")]
public string ContactName { get; set; }
public bool Enabled { get; set; }
public int? RoleID { get; set; }
public virtual Role Role { get; set; }
public string Signature { get; set; }
public int? ParentUserID { get; set; }
public virtual User ParentUser { get; set; }
public virtual List<User> ChildUsers { get; set; }
public virtual List<UserCategory> UserCategories { get; set; }
[NotMapped]
public string NewPassword { get; set; }
public User()
{
Enabled = true;
}
}
public class Application
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ApplicationID { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
public string ContactName { get; set; }
[Column(TypeName = "datetime2")]
public DateTime ApplicationDate { get; set; }
public int ApplicationStatusID { get; set; }
public virtual ApplicationStatus ApplicationStatus { get; set; }
public virtual List<Product> Products { get; set; }
public bool Enabled { get; set; }
[NotMapped]
public int ProductsQuantity { get; set; }
public Application()
{
Enabled = true;
}
}
這就是我正在做的
using (var context = new ClientDbContext())
{
IQueryable<Application> query;
if (model.UserID > 0 && model.ApplicationStatusID > 0)
query = context.Applications
.Include(x => x.ApplicationStatus)
.Include(x => x.Products)
.Where(x => x.UserID == model.UserID && x.ApplicationStatusID == model.ApplicationStatusID && x.Enabled == true);
else if (model.UserID == 0 && model.ApplicationStatusID > 0)
query = context.Applications
.Include(x => x.ApplicationStatus)
.Include(x => x.Products)
.Where(x => x.ApplicationStatusID == model.ApplicationStatusID && x.Enabled == true);
else if (model.UserID > 0 && model.ApplicationStatusID == 0)
query = context.Applications
.Include(x => x.ApplicationStatus)
.Include(x => x.Products)
.Where(x => x.UserID == model.UserID && x.Enabled == true);
else
query = null;
foreach (var item in query)
{
item.ProductsQuantity = item.Products.Count();
}
response = new UtilitariesResponse<Application>(config).setResponseBaseForList(query);
}
您的要求:
如果用戶是經理,則獲取他的應用程序,但如果是經銷商,則獲取他的應用程序,包括他的孩子的應用程序。
我不確定您是否使用實體框架。 如果是這樣,你會讓你的生活變得更加困難,因為你偏離了實體框架約定
你說每個用戶都有零個或多個 ChildUsers,每個用戶都有零個或一個 ParentUser,由外鍵 ParentUserId 引用。
類似地,用戶和應用程序之間存在一對多關系:每個用戶都有零個或多個應用程序,每個應用程序只屬於一個用戶,由外鍵 UserId 引用。
在實體框架中編寫這些關系的正確方法是:
class User
{
public int UserId {get; set;}
// every User has zero or more Applications (one-to-many)
public virtual ICollection<Application> Applications {get; set;}
// every User has zero or more ChildUsers (one-to-many)
public virtual ICollection<User> ChildUsers {get; set}
// every User belongs to zero or one ParentUser, using foreign key
public int ParentUserId {get; set;}
public virtual User ParentUser {get; set;}
... // all other properties are not important in your question.
}
如果用戶是經理,則獲取他的應用程序,但如果是經銷商,則獲取他的應用程序,包括他孩子的應用程序。
如果用戶是管理員,您希望應用程序與子應用程序如何:作為一個應用程序序列,還是作為一個應用程序序列,其中每個應用程序都有零個或多個子應用程序?
您如何決定用戶是否是經理並不重要,讓我們假設用戶有一個屬性:
public bool IsManager {get => ...}
IQueryable<User> Users = ClientDbContext.Users
// only if you don't want all Users:
.Where(user => ...)
這個想法是,讓兩組用戶:經理和其他人。 如果用戶不是經理,我們將選擇請求的屬性,包括應用程序; 如果用戶是經理,我們也會選擇子應用程序。
var result = Users.Select(user => new
{
// Select the properties that both Managers and Others need:
Id = user.Id,
Name = user.Name
...
Applications = User.Applications.Select(application => new
{
// Select the application properties that you plan to use:
Id = application.Id,
...
// not needed: you already know the value
// UserId = application.UserId,
},
// if the user is a Manager, add the ChildApplications, otherwise add empty collection
ChildApplications = (User.IsManager ?
User.ChildUsers.SelectMany(childUser => childUser.Applications) :
Enumerable.Empty<Application>())
.Select(childApplication => new
{
// select the properties that you want from the child application
})
.ToList(),
});
看部分:
ChildApplications = (User.IsManager ?
User.ChildUsers.SelectMany(childUser => childUser.Applications) :
Enumerable.Empty<Application>())
這部分檢查用戶是否是經理。 是這樣,它將所有子用戶的所有應用程序作為一個大序列(SelectMany 而不是 Select)。 如果用戶不是經理,他會獲取一個空的應用程序集合。
從結果中的每個應用程序(ChildUsers 的所有應用程序的集合,或空集合)中,我們選擇您想要的屬性。
雖然這有效,但效率不高,因為每個應用程序調用一次 IsManager。 考慮進行兩項查詢:一項針對經理,一項針對其他人。 不執行查詢,而是選擇相同的屬性並連接查詢。 然后執行它們,這樣您就可以確定您的 DBMS 只被聯系一次。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.