Задача: в базе хранятся теги и теги к контенту (связь тег-контент).
Пользователь вводит свои теги (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();
}