Проблема
Моя концепция заключается в том, что когда пользователь создает сообщение с некоторыми тегами, сервер сначала проверяет, существует ли уже имя тега, если оно существует, его счетчик увеличивается, в противном случае новый тег создан.
Проблема возникает, когда несколько пользователей создают сообщение одновременно с новым тегом, скажем, new_tag
, тогда несколько тегов с тем же именем сохраняются в базе данных вместо 1 тега с counter = Количество пользователей, которые использовали этот тег
Как видите, для каждого пользователя в базе данных создается новая запись тега:
--------------------------------
| id | tagName | counter |
|------|-----------|-----------|
| 1 | new_tag | 1 |
| 2 | new_tag | 1 |
| 3 | new_tag | 1 |
| 4 | new_tag | 1 |
--------------------------------
Что я ожидаю:
--------------------------------
| id | tagName | counter |
|------|-----------|-----------|
| 1 | new_tag | 4 |
--------------------------------
Этот код показывает, как я реализовал персистентность:
PostRepository
public async Task<bool> AddAsync(Post entity)
{
await AddNewTagsAsync(entity);
_context.Attach(entity.Event);
await _context.AddAsync(entity);
await _context.Database.BeginTransactionAsync();
var result = await _context.SaveChangesAsync();
_context.Database.CommitTransaction();
return result > 0;
}
public async Task AddNewTagsAsync(Post post)
{
// store tags name in lower case
if ((post.PostTags == null) || (post.PostTags.Count==0))
return;
post.PostTags.ForEach(pt => pt.Tag.TagName = pt.Tag.TagName.ToLower());
for(var i =0; i<post.PostTags.Count; i++)
{
var postTag = post.PostTags[i];
// here lays the main problem, when many concurrent users check for tag existence
// all get null and new tag will be created, workaround needed!
var existingTag = await _context.Tags.SingleOrDefaultAsync(x => x.TagName == postTag.Tag.TagName);
// if tag exists, increment counter
if (existingTag != null)
{
existingTag.Counter++;
postTag.Tag = existingTag;
continue;
}
// else the new Tag object will be peristed
}
}
Это часть моей ER Диаграмма:
Просто отметим, что это работает должным образом, если один пользователь сначала создает тег, а другие просто увеличивают счетчик и используют то же самое. тег