【问题标题】:rework linq query to returns nested objects返工 linq 查询以返回嵌套对象
【发布时间】:2019-12-12 13:52:00
【问题描述】:

我有一个这样的数据库表

我的查询 linq 看起来像

   var selectedNotifications = _dbContext.UserNotificationTypeDeliveryChoice
    .Include(m => m.NotificationGroup)
    .Include(m => m.DeliveryType)
    .Where(m => m.UserDefId == userDefId && m.UserTypeId == (int)userType)
    .Select(m => new NotificationGroup()
    {
      NotificationGroupId = m.NotificationGroup.NotificationGroupId,
      Name = m.NotificationGroup.Name,
      DefaultDeliveryType = m.DeliveryType,
      HasChoosen = true
    }).ToList();

在我的模型中,我使用虚拟道具来填写外键属性 DeliveryType。 它看起来像这样(JSON):

[
  {
    "notificationGroupId": 1,
    "name": "Comments",
    "defaultDeliveryType": {
      "deliveryTypeId": 2,
      "name": "Email"
    },
    "hasChoosen": true
  },
  {
    "notificationGroupId": 2,
    "name": "Q&A",
    "defaultDeliveryType": {
      "deliveryTypeId": 2,
      "name": "Email"
    },
    "hasChoosen": true
  },
  {
    "notificationGroupId": 3,
    "name": "Services",
    "defaultDeliveryType": {
      "deliveryTypeId": 2,
      "name": "Email"
    },
    "hasChoosen": true
  },
  {
    "notificationGroupId": 4,
    "name": "Trial",
    "defaultDeliveryType": {
      "deliveryTypeId": 2,
      "name": "Email"
    },
    "hasChoosen": true
  },
  {
    "notificationGroupId": 4,
    "name": "Trial",
    "defaultDeliveryType": {
      "deliveryTypeId": 1,
      "name": "SMS"
    },
    "hasChoosen": true
  }
]

但是,我有多个相同 NotificationGroupId 的记录,我希望列出如下:

[
  {
    "notificationGroupId": 4,
    "name": "Trial",
    "defaultDeliveryType": {
      "deliveryTypeId": 1,
      "name": "SMS"
    },
    "defaultDeliveryType": {
        "deliveryTypeId": 2,
        "name": "Email"
      },
    "hasChoosen": true
  }
]

请注意“notificationGroupId”的区别:4,它需要有嵌套的传递类型。

更新 #1 我设法实现了一些目标,但我仍然需要使用 Select 投影仪语句映射到我的模型。

这是一个例子:

var selectedNotifications = _dbContext.UserNotificationTypeDeliveryChoice
                            .Include(m => m.NotificationGroup)
                            .Include(m => m.DeliveryType)
                            .Where(m => m.UserDefId == userDefId && m.UserTypeId == (int)userType)
                            .GroupBy(p => p.NotificationGroupId,
                                     p => p.DeliveryType,
                                     (key, g) => new { NotificationGroupId = key, DeliveryTypes = g });

更新 #2强文本

    public class UserNotificationTypeDeliveryChoice
    {
        public List<NotificationGroup> NotificationGroups { get; set; }
        //public List<DeliveryType> DeliveryTypes { get; set; }
        public long UserNotificationTypeDeliveryChoiceId { get; set; }
        public int? UserDefId { get; set; }
        public int? UserCompanyOrInstitutionId { get; set; }
        public byte NotificationGroupId { get; set; }
        public byte DeliveryTypeId { get; set; }
        public int UserTypeId { get; set; }
        public virtual DeliveryType DeliveryType { get; set; }
        public virtual NotificationGroup NotificationGroup { get; set; }
        public virtual UserDef UserDef { get; set; }
    }

NotificationGroup 和 DeliveryType 的模型:

    public class NotificationGroup
    {
        public NotificationGroup()
        {
            UserNotificationTypeDeliveryChoice = new HashSet<UserNotificationTypeDeliveryChoice>();
            NotificationGroupUserType = new HashSet<NotificationGroupUserType>();
        }
        //public List<DeliveryType> DeliveryTypes { get; set; }
        public byte NotificationGroupId { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        //public bool HasChoosen { get; set; }
        public virtual DeliveryType DefaultDeliveryType { get; set; }
        public byte DefaultDeliveryTypeId { get; set; }
        public virtual ICollection<UserNotificationTypeDeliveryChoice> UserNotificationTypeDeliveryChoice { get; set; }
        public virtual ICollection<NotificationGroupUserType> NotificationGroupUserType { get; set; }
    }

    public class DeliveryType
    {
        public DeliveryType()
        {
            NotificationGroup = new HashSet<NotificationGroup>();
            UserNotificationTypeDeliveryChoice = new HashSet<UserNotificationTypeDeliveryChoice>();
            NotificationGroupUserType = new HashSet<NotificationGroupUserType>();
        }

        public byte DeliveryTypeId { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }

        public virtual ICollection<NotificationGroup> NotificationGroup { get; set; }
        public virtual ICollection<UserNotificationTypeDeliveryChoice> UserNotificationTypeDeliveryChoice { get; set; }
        public virtual ICollection<NotificationGroupUserType> NotificationGroupUserType { get; set; }
    }
}

这是我通过 EF Core 映射的模型描述:

【问题讨论】:

  • 你不能只使用notificationGroupId的分组吗?此外,defaultDeliveryType 必须更改为列表。因为如果您分组,每个 notificationGroup 可以有多个。
  • @jpgrassi 是的!有用。但我没有映射到我的模型我只有匿名属性。请看我的更新#1
  • .GroupBy 之后,您可以执行.Select 并投影到您需要的任何内容。创建反映所需 JSON 的新模型并相应地填充它们。
  • 是的,但我还需要一个名称才能从 GroupBy 中提取,我该怎么做?
  • @Stefan89BEG 你的名字在这里DeliveryTypes = g 如果你只想要名字,它会是DeliveryTypes = g.Select(x =&gt; x.name) 但他不是你想要的输出。

标签: c# asp.net-mvc linq asp.net-core


【解决方案1】:

如果你有一个非唯一的 ID,你不能按 NotificationGroup 分组,你必须坚持使用 ID。

要保留 NotifigrationGroup 的名称,您必须将 NotificationGroup 保留为 GroupBy 的 TElement。 (这就是为什么 p=>p。)

稍后在结果选择器中,您可以从其中一个元素中选择一个名称,只需选择第一个 NotificationGroup 的名称。如果您愿意,您可以在此处选择 DeliveryTypes。

var selectedNotifications = _dbContext.UserNotificationTypeDeliveryChoice
                            .Include(m => m.NotificationGroup)
                            .Include(m => m.DeliveryType)
                            .Where(m => m.UserDefId == userDefId && m.UserTypeId == (int)userType)
                            .GroupBy( p => p.NotificationGroupId, p => p, 
                    (key,g) => new { 
                         NotificationId = key, 
                         Name = g.First().Name, 
                         DeliveryTypes = g.Select(x => x.DeliveryTypes)
                               }););

【讨论】:

  • 请记住我包括了其他表,所以这里 groupBy 是通过指向 NotificationGroup 的 FK Id 进行的,仍然崩溃,因为它说 Invalid column UserNotificationTypeDeliveryChoiceId
  • 不,不是。在您的模型中,外键必须没问题,才能使您的两个包含工作。他们解决了这些关系。这与 GroupBy 完全无关。如果没有看到 C# 类或没有调试器,很难告诉您出了什么问题。 g 是 UserNotificationTypeDeliveryChoice 的集合吗?好吧,不是 g.First().NotificationGroup.Name。
  • 如何在同一个类中有一个单一的 NotficationGroup 和一个 List ?这是没有意义的。它看起来像一个循环引用,我认为 EntityFramework 会拒绝创建这样的数据库导致多个删除级联。
  • 我先做 db,我手动为 ef core 添加上下文。用于与 EntityTypeBuilder 进行映射,称为导航属性
  • 有趣的是,它确实有效,但是当我删除传递类型的 Select 子句时,如果我放置一些与 g 匿名相关的属性,它会崩溃
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-21
  • 2018-09-09
  • 2021-12-10
  • 2019-08-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多