Задача: в базе хранятся теги и теги к контенту (связь тег-контент).
Пользователь вводит свои теги (String[] tagTitles) к контенту.
Среди введенных пользователем тегов могут быть как совсем новые, так и уже существующие в базе.
Новые теги необходимо добавить в таблицу тегов и в таблицу связи тег-контент.
У уже существующих тегов необходимо увеличить поле количества использований на 1.
Структура таблиц
[Table("ContentTag")] public class ContentTag { public int Id { get; set; } public int TagId { get; set; } public virtual Tag Tag { get; set; } public int ContentId { get; set; } public int TimesUsed { get; set; } } [Table("Tag")] public class Tag { public int Id { get; set; } public string Title { get; set; } public string Description { get; set; } public int TimesUsed { get; set; } }
Функция с багом
private void AttachTagsToContent(String[] tagTitles, Content content) { var tags_ = tagTitles.GroupJoin( this.dbContext.Tag, title => title, tag => tag.Title, (title, tag) => new { Title = title, Tag = tag.FirstOrDefault(), IsNew = tag.Any() == false }); var newTags = tags_.Where(tag => tag.IsNew).Select(tag => tag.Title); var tagsAndContentTagsToUpdate = tags_ .Where(tag => tag.IsNew == false) .Select(tag => tag.Tag) .Join( this.dbContext.ContentTags, tag => tag.Id, contentTag => contentTag.Tag.Id, (tag, contentTag) => new { Tag = tag, ContentTag = contentTag }); foreach (var title in newTags) { var tag = new Tag() { Title = title }; var contentTag = new ContentTag() { ContentId = content.Id, Tag = tag }; this.dbContext.ContentTags.Add(contentTag); } foreach (var tagAndContentTag in tagsAndContentTagsToUpdate) { tagAndContentTag.Tag.TimesUsed++; tagAndContentTag.ContentTag.TimesUsed++; } this.dbContext.SaveChanges(); }
В чем собственно баг.
Теги и теги к контенту.
Варианты:
Тега нет ни в тегах, ни в контенте — тег добавляется в теги и в контент
Тег есть в тегах, но нет в контенте — тег плюсуется в тегах и добавляется в контент
Тег есть и в тегах и в контенте — тег плюсуется в тегах и в контенте
Тега нет в тегах, но есть в контенте — это ошибка, такого не должно быть
Пусто везде.
750: «мухи», «собаки», «медведи», «старый тег»
Добавились в две таблицы
610: «мухи», «собаки», «медведи», «старый тег»
Увеличились в тегах, увеличились в контенте у 750й
610: «кошки», «мышки», «носороги», «новый тег»
Добавились в обе таблицы
610: «мухи», «собаки», «медведи»
Увеличились в тегах, увеличились у 750й
610: «кошки», «мышки», «носороги»
Увеличиличь в тегах, увеличились у 610й
609: «кошки», «мышки», «носороги», «пулемет»
кмн увеличились, п добавился
кмн увеличиличь у 610й, п добавился к 609й
833: «кошки», «собаки», «огурец»
в тегах добавилось-увеличилось как надо,
в тег-контенте собаки увеличились у 750, кошки — у 610, к 833 добавился только огурец
почему-то если тег есть в таблице тегов и у какого-то контента, то если мы пытаемся добавить этот тег к другому контенту, то он увеличивается у первого
Измененный вариант с исправленным багом
private void AttachTagsToContent(String[] tagTitles, Content content) { var tags_ = tagTitles.GroupJoin( this.dbContext.Tag, title => title, tag => tag.Title, (title, tag) => new { Title = title, Tag = tag.FirstOrDefault(), IsNew = tag.Any() == false }); var newTags = tags_.Where(tag => tag.IsNew).Select(tag => tag.Title); var tagsAndContentTagsToUpdate = tags_ .Where(tag => tag.IsNew == false) .Select(tag => tag.Tag) .GroupJoin( this.dbContext.ContentTags, tag => tag.Id, contentTag => contentTag.Tag.Id, (tag, contentTag) => new { Tag = tag, ContentTag = contentTag.SingleOrDefault(ct => ct.ContentId == content.Id) }); foreach (var title in newTags) { var tag = new Tag() { Title = title }; var contentTag = new ContentTag() { ContentId = content.Id, Tag = tag }; this.dbContext.ContentTags.Add(contentTag); } foreach (var tagAndContentTag in tagsAndContentTagsToUpdate) { tagAndContentTag.Tag.TimesUsed++; if (tagAndContentTag.ContentTag == null) { var contentTag = new ContentTag() { ContentId = content.Id, Tag = tagAndContentTag.Tag }; this.dbContext.ContentTags.Add(contentTag); } else { tagAndContentTag.ContentTag.TimesUsed++; } } this.dbContext.SaveChanges(); }