Используя LINQ-to-Entities 4.0, существует ли правильный шаблон или конструкция для безопасной реализации «если не существует, то вставьте»?
Например, у меня в настоящее время есть таблица, которая отслеживает «избранное пользователя» -пользователи могут добавлять или удалять статьи из своего списка избранного.
Базовая таблица не является истинным отношением «многие ко многим», но вместо этого отслеживает некоторую дополнительную информацию, например дату добавления избранного.
CREATE TABLE UserFavorite
(
FavoriteId int not null identity(1,1) primary key,
UserId int not null,
ArticleId int not null
);
CREATE UNIQUE INDEX IX_UserFavorite_1 ON UserFavorite (UserId, ArticleId);
Вставка двух избранных с одной и той же парой пользователь / статья приводит к ошибке дублированного ключа, если необходимо.
В настоящее время я реализовал логику «если не существует, то вставьте» на уровне данных с использованием C #:
if (!entities.FavoriteArticles.Any(
f => f.UserId == userId &&
f.ArticleId == articleId))
{
FavoriteArticle favorite = new FavoriteArticle();
favorite.UserId = userId;
favorite.ArticleId = articleId;
favorite.DateAdded = DateTime.Now;
Entities.AddToFavoriteArticles(favorite);
Entities.SaveChanges();
}
Проблема этой реализации заключается в том, что она подвержена условиям гонки.Например, если пользователь дважды щелкнет ссылку «добавить в избранное», на сервер могут быть отправлены два запроса.Первый запрос выполняется успешно, в то время как второй (тот, который видит пользователь) завершается с ошибкой UpdateException, обертывающей SqlException для ошибки дублирующего ключа.
С помощью хранимых процедур T-SQL я могу использовать транзакции с подсказками блокировки, чтобысостояние гонки никогда не возникает.Существует ли чистый метод для предотвращения состояния гонки в Entity Framework без использования хранимых процедур или слепого проглатывания исключений?