c# entity-framework entity-framework-5 upsert

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();