簡體   English   中英

包含自引用子項的查詢表

[英]Query table including selfreference childs

抱歉標題含糊不清,我不知道如何正確解析它。
我必須有 2 個表, UsesApplications一對多,Users 引用自身。 用戶可以是DealerManager ,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.

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