LINQ - Добавление записи, где вложенное значение содержит значение из другого массива - PullRequest
0 голосов
/ 18 июня 2019

Я хочу добавить запись уведомления своим пользователям с базой данных SQL, используя Entity Framework и LINQ. У моих пользователей уже есть вложенный массив тегов, которые они выбрали. Я хотел бы добавить запись уведомления пользователю, если его выбранные теги содержат какой-либо тег, включенный в теги массива, которые я передаю в свой метод.

Вот как выглядит мой массив 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"
}

У моих пользователей есть связанный с ними вложенный массив тегов, который также выглядит как массив тегов выше и имеет те же идентификаторы.

Мой метод сейчас такой:

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 ]

1 голос
/ 18 июня 2019

Вы можете столкнуться с проблемами, связанными с тегами, если они не являются объектами, связанными с текущим контекстом или запросом.Кроме того, является ли Уведомление новым объектом или представляет запись, которая уже существует в базе данных?Ожидается ли, что контекст узнает об этом?

При поиске связей на основе критериев я обычно выбираю работу с идентификаторами, поскольку это упрощает запрос на совпадения.Например:

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);
    }
}

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

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

Объекты, передаваемые в такие вещи, как действия контроллера, десериализованы, так что в отношении DbContext они ничем не отличаются от кода, подобного:

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

Неважно, что ранее уведомление загружалось из DbContext.Это был другой экземпляр DbContext, и объект был сериализован и десериализован.EF будет воспринимать это как новую запись.Если PK сконфигурирован как Identity, вы получите новую запись с новым NotificationID.Если PK не настроен, вы получите нарушение ключа, когда EF попытается вставить дублирующую строку.Вы можете связать его с DbContext с помощью Attach() и установить для состояния «Изменено», но это подвергает вашу систему значительному риску подделки, поскольку клиенты могут изменять эту сущность так, как вы этого не ожидаете, изменяя FK или другие значения, которые вы используете.Пользовательский интерфейс не разрешает и не перезаписывает данные.

1 голос
/ 18 июня 2019

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

var usersToAddTheNotificationTo = DbContext.Users
        .Where(User.Tags.Intersect(tags).Count() > 0).ToList();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...