Таблица запросов, включая собственные ссылки childs - PullRequest
0 голосов
/ 19 марта 2020

Извините за смутный заголовок, я не знаю, как его правильно проанализировать.
У меня есть 2 таблицы, Uses и Applications один-ко-многим, и пользователи ссылаются на себя. Пользователь может быть Dealer или Manager, 1 дилер со многими менеджерами. В настоящее время я могу получить все приложения по UserID, но я не мог понять, как включить childs, если пользователь 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);

                }

1 Ответ

0 голосов
/ 19 марта 2020

Ваше требование:

, если пользователь является менеджером, тогда получите его заявки, но если дилер получит его приложения, включая его дочерние приложения.

Я не уверен, вы используете структуру объекта или нет. Если это так, вы усложняете свою жизнь, потому что вы отклоняетесь от соглашений о структуре сущностей

Вы говорите, что у каждого пользователя ноль или более ChildUsers, а у каждого пользователя ноль или один ParentUser, ссылается по внешнему ключу ParentUserId.

Аналогично существует отношение один-ко-многим между Пользователями и Приложениями: каждый Пользователь имеет ноль или более Приложений, каждое Приложение принадлежит ровно одному Пользователю, на который ссылается внешний ключ UserId.

Правильный способ записи этих отношений в Entity Framework будет выглядеть следующим образом:

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.
}

, если пользователь является Manager, тогда получают его приложения, но если Дилер получает его приложения, включая его дочерние приложения.

Если пользователь является менеджером, как вы хотите, чтобы приложения с дочерними приложениями: как одна последовательность приложений или как одна последовательность приложений, где каждое приложение имеет ноль или более дочерних приложений? ?

Не важно, как вы решаете, Пользователь является менеджером или нет, давайте предположим, что у пользователя есть свойство:

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>())

Эта часть проверяет, является ли пользователь менеджером. Таким образом, он принимает все Приложения от всех ChildUsers как одну большую последовательность (SelectMany вместо Select). Если пользователь не является менеджером, он берет пустую коллекцию приложений.

Из каждого приложения в результате (либо из коллекции всех приложений ChildUsers, либо из пустой коллекции) мы выбираем свойства, которые вы want.

Хотя это работает, это не очень эффективно, потому что IsManager вызывается один раз для каждого приложения. Подумайте о создании двух запросов: один для менеджеров и один для других. Не выполняйте запрос, но выберите те же свойства и выполните запросы. Затем выполните их, чтобы убедиться, что к вашей СУБД обращаются только один раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...