Usando LINQ-to-Entities 4.0, ¿existe un patrón o construcción correcto para implementar de forma segura "if not exists then insert"?Implementando if-not-exists-insert usando Entity Framework sin condiciones de carrera
Por ejemplo, actualmente tengo una tabla que rastrea "favoritos de usuario": los usuarios pueden agregar o eliminar artículos de su lista de favoritos.
La tabla subyacente no es una verdadera relación muchos a muchos, sino que rastrea información adicional como la fecha en que se agregó el favorito.
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);
La inserción de dos favoritos con el mismo par de Usuario/Artículo da como resultado un error de clave duplicado, según se desee.
he implementado actualmente la lógica "si no existe, entonces insertar" en la capa de datos usando 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();
}
El problema de esta aplicación es que es susceptible a las condiciones de carrera. Por ejemplo, si un usuario hace doble clic en el enlace "agregar a favoritos", se podrían enviar dos solicitudes al servidor. La primera solicitud se realiza correctamente, mientras que la segunda solicitud (la que el usuario ve) falla con una excepción de actualización que envuelve una SqlException para el error de clave duplicada.
Con los procedimientos almacenados de T-SQL puedo usar transacciones con consejos de bloqueo para garantizar que nunca se produzca una condición de carrera. ¿Existe un método limpio para evitar la condición de carrera en Entity Framework sin recurrir a procedimientos almacenados o excepciones para tragar ciegamente?
¿has echado un vistazo a 'using (var trantra = new TransactionScope())'? – RPM1984