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

时间:2019-06-17 21:28:31

标签: c# arrays entity-framework linq tags

我希望使用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);
    }
}

我怎么能做到这是最简单的方法?

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

您可能会遇到关联标记的问题,这些标记不是与当前上下文或查询关联的实体。另外,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);

传递给诸如Controller动作之类的实体进行反序列化,因此就DbContext而言,它们与诸如以下的代码没有区别:

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

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