c# - AddOrUpdate no funciona como se espera y produce duplicados
entity-framework entity-framework-5 (2)
Primero (aún no hay respuesta), se puede llamar a AddOrUpdate
con una matriz de nuevos objetos, por lo que puede crear una matriz de tipo City[]
y llamar a context.CitySet.AddOrUpdate(cc => cc.Id, cityArray);
una vez.
(editado)
En segundo lugar, AddOrUpdate
usa la expresión de identificador ( cc => cc.Id
) para buscar ciudades con el mismo Id
que las de la matriz. Estas ciudades serán actualizadas. Las otras ciudades de la matriz se insertarán, pero la base de datos generará sus valores de Id
, porque Id
es una columna de identidad. No se puede establecer mediante una instrucción de inserción. (A menos que establezca Identity Insert on). Entonces, al usar AddOrUpdate
para tablas con columnas de identidad, debe encontrar otra forma de identificar registros porque los valores de identificación de los registros existentes son impredecibles.
En su caso, utilizó Slug
como identificador para AddOrUpdate
, que debe ser único (según su comentario). No me queda claro por qué eso no actualiza los registros existentes con los Slug
correspondientes.
Configuré una pequeña prueba: agregue o actualice una entidad con un Id (iedntity) y un nombre único:
var n = new Product { ProductID = 999, ProductName = "Prod1", UnitPrice = 1.25 };
Products.AddOrUpdate(p => p.ProductName, n);
SaveChanges();
Cuando "Prod1" aún no está allí, se inserta (ignorando Id 999).
Si es y UnitPrice
es diferente, se actualiza.
En cuanto a las consultas emitidas, veo que EF está buscando un registro único por nombre:
SELECT TOP (2)
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName],
[Extent1].[UnitPrice] AS [UnitPrice]
FROM [dbo].[Products] AS [Extent1]
WHERE N''Prod1'' = [Extent1].[ProductName]
Y luego (cuando se encuentra una coincidencia y UnitPrice
es diferente)
update [dbo].[Products]
set [UnitPrice] = 1.26
where ([ProductID] = 15)
Esto muestra que EF encontró un registro y ahora usa el campo clave para hacer la actualización.
Espero que ver este ejemplo arroje algo de luz sobre su situación. Tal vez debería monitorear las sentencias de SQL también y ver si algo inesperado ocurre allí.
Estoy usando la configuración de EF5 basada en Code-First DBContext.
En DbMigrationsConfiguration.Seed
estoy tratando de llenar DB con datos ficticios predeterminados. Para realizar esta tarea, uso el método DbSet.AddOrUpdate
.
El código más simple para ilustrar mi objetivo:
j = 0;
var cities = new[]
{
"Berlin",
"Vienna",
"London",
"Bristol",
"Rome",
"Stockholm",
"Oslo",
"Helsinki",
"Amsterdam",
"Dublin"
};
var cityObjects = new City[cities.Length];
foreach (string c in cities)
{
int id = r.NextDouble() > 0.5 ? 0 : 1;
var city = new City
{
Id = j,
Name = c,
Slug = c.ToLowerInvariant(),
Region = regions[id],
RegionId = regions[id].Id,
Reviewed = true
};
context.CitySet.AddOrUpdate(cc => cc.Id, city);
cityObjects[j] = city;
j++;
}
He intentado usar / omitir el campo Id
, así como usar la propiedad Id
/ Slug
como selector de actualización.
cuando se ejecuta Update-Database
, el campo Id
se ignora y SQL Server genera automáticamente el valor y la base de datos se llena con duplicados; Slug
selector de Slug
permite duplicados y en las ejecuciones posteriores produce excepciones (la Sequence contains more than one element
).
¿ AddOrUpdate
método AddOrUpdate
está destinado a funcionar de esta manera? ¿Debo realizar upsert a mano?
var paidOutType = new List<PaidOutType>
{
new PaidOutType { PaidOutTypeID = 1, Code = "001", Description = "PAID OUT 1", PType = "1", Amount = 0, IsSalesSummery = true,DayFrom=1,DayTo=31 },
new PaidOutType { PaidOutTypeID = 2, Code = "002", Description = "PAID OUT 2", PType = "1", Amount = 0, IsSalesSummery = true,DayFrom=1,DayTo=31 },
new PaidOutType { PaidOutTypeID = 3, Code = "002", Description = "PAID OUT 3", PType = "1", Amount = 0, IsSalesSummery = true,DayFrom=1,DayTo=31 },
};
paidOutType.ForEach(u => smartPOSContext.PaidOutType.AddOrUpdate(u));
smartPOSContext.SaveChanges();