繁体   English   中英

LINQ-添加记录,其中嵌套的值包含来自另一个数组的值

[英]LINQ - Adding record where nested value contains value from another array

我正在使用Entity Framework和LINQ向使用SQL数据库的用户添加通知记录。 我的用户已经具有他们选择的嵌套标签数组。 如果用户选择的标签包含我传递给我的方法的数组标签中包含的任何标签,我想向用户添加通知记录。

这是我的Tag数组的样子:

[
  {
    "Id": 2,
    "Text": "Blue",
    "Value": "blue"
  },
  {
    "Id": 4,
    "Text": "Red",
    "Value": "red"
  },
  {
    "Id": 3,
    "Text": "White",
    "Value": "white"
  }
]

我的通知如下所示:

{
    "Image": "https://www.image.com",
    "Heading": "Example heading",
    "Content": "Example content"
}

我的用户有一个与其关联的嵌套标签数组,该数组看起来也类似于上面的标签数组,并且具有相同的ID。

我的方法目前是这样的:

AddUserNotification(Notification notification, IList<Tag> tags) 
{
    var usersToAddTheNotificationTo = DbContext.Users
        .Where(User.Tags.Contains(tags)).ToList();

    foreach(var user in usersToAddTheNotificationTo) 
    {
          user.Notifications.Add(notification);
    }
}

如何实现这是最简单的方法?

您想要做的是在用户标签和通知标签之间建立交集 ,并且如果此新交集数量不为空,则要添加通知

var usersToAddTheNotificationTo = DbContext.Users
        .Where(User.Tags.Intersect(tags).Count() > 0).ToList();

您可能会遇到关联标记的问题,这些标记不是与当前上下文或查询关联的实体。 另外,Notification是新实体,还是代表数据库中已经存在的记录? 是否希望上下文知道这一点?

当寻求基于条件进行关联时,我通常会选择使用ID,因为这样可以更轻松地查询匹配项。 例如:

public void AddUserNotification(Notification notification, IList<int> tagIds) 
{
    var usersToAddTheNotificationTo = DbContext.Users
        .Where(x => x.Tags.Any(t => tagIds.Contains(t.TagId)).ToList();

    foreach(var user in usersToAddTheNotificationTo) 
    {
          user.Notifications.Add(notification);
    }
}

在不更改签名的情况下:

public void AddUserNotification(Notification notification, IList<Tag> tags) 
{
    var tagIds = tags.Select(x => x.TagId).ToList();
    var usersToAddTheNotificationTo = DbContext.Users
        .Where(x => x.Tags.Any(t => tagIds.Contains(t.TagId)).ToList();

    foreach(var user in usersToAddTheNotificationTo) 
    {
          user.Notifications.Add(notification);
    }
}

另一种警告:如果Notification表示一个现有记录,那么您还应该根据ID从上下文中加载它。

var existingNotification = DbContext.Notifications.Single(x => x.NotificationId == notification.NotificationId);

传递给控制器​​动作之类的实体是反序列化的,因此就DbContext而言,它们与以下代码没有区别:

var notification = new Notification { NotificationId = 16, .... };

早先从DbContext加载通知都没关系。 这是一个不同的DbContext实例,并且该实体已序列化和反序列化。 EF会将其视为新记录。 如果PK被配置为身份,您将获得一条插入了新NotificationID的新记录。 如果未配置PK,则在EF尝试插入重复行时会遇到密钥冲突。 您可以使用Attach()其与DbContext关联,并将State设置为“ Modified”,但这会使您的系统面临很大的篡改风险,因为客户端可能会以您不希望的方式更改该实体,更改FK或您的其他值UI不允许并覆盖数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM