2010-11-18 11 views
79

Digamos que consulto la base de datos y cargo una lista de artículos. A continuación, abro uno de los elementos en una vista detallada, y en lugar de volver a consultar el elemento fuera de la base de datos, creo una instancia del elemento del origen de datos en la lista.¿Desea actualizar un registro sin consultar primero?

¿Hay alguna forma de actualizar el registro de la base de datos sin obtener el registro del elemento individual?

Este es un ejemplo de cómo lo estoy haciendo ahora:

dataItem itemToUpdate = (from t in dataEntity.items 
           where t.id == id 
           select t).FirstOrDefault(); 

A continuación, después de tirar el disco que actualizar algunos valores en el artículo y pulsar el récord de vuelta:

itemToUpdate.itemstatus = newStatus; 
dataEntity.SaveChanges(); 

Me gustaría pensar habría una mejor manera de hacer esto, ¿alguna idea?

+2

No es una manera terriblemente mala de hacer las cosas. ¿Tiene acceso concurrente a esa mesa? –

+0

Creo que este es el uso que un ORM como EF está ahí para servir. ¿Permitir que las operaciones dentro del contexto de la aplicación se realicen en los objetos que desea crear/modificar/eliminar, sin preocuparse por la implementación subyacente de DB? –

+27

Creo que para los desarrolladores con experiencia en TSQL tratando de aceptar y aceptar ORM's, es un poco ineficiente buscar un registro solo para actualizarlo, y nunca utilizar los datos obtenidos. Este concepto de que un desarrollador no necesita preocuparse por la implementación subyacente de DB es una bazofia. Cuanto más sepa un desarrollador sobre todo el sistema, mejor podrá ser la solución. Las opciones nunca son malas. – barrypicker

Respuesta

61

Debe utilizar el método Attach().

Attaching and Detaching Objects

+13

puede dar un ejemplo? –

+14

context.Products.Attach (producto); context.Entry (producto) .State = EntityState.Modified; – Gabriel

+4

@Gabriel ¿Esto no actualizará todas las propiedades? ¿Qué pasa si solo quiero modificar una sola? –

0

En términos generales, si se ha utilizado Entity Framework para consultar todos los artículos, y ha guardado el objeto de entidad, se puede actualizar los elementos individuales en el objeto entidad y llamar SaveChanges() cuando haya terminado. Por ejemplo:

var items = dataEntity.Include("items").items; 
// For each one you want to change: 
items.First(item => item.id == theIdYouWant).itemstatus = newStatus; 
// After all changes: 
dataEntity.SaveChanges(); 

La recuperación del artículo que desea no debe generar una nueva consulta.

+0

Interesante respuesta, ¿alguien más ha confirmado esto? – Ian

+3

Hace lo mismo que el problema de OP: recupera todo el registro y luego lo actualiza. .Primero() deserializa el objeto. – Jerther

27

También puede usar SQL directo en la base de datos utilizando el contexto del almacén de datos. Ejemplo:

dataEntity.ExecuteStoreCommand 
    ("UPDATE items SET itemstatus = 'some status' WHERE id = 123 "); 

Por motivos de rendimiento, es posible que desee pasar variables en lugar de una única cadena de SQL codificada. Esto permitirá que SQL Server guarde en caché la consulta y la reutilice con parámetros. Ejemplo:

dataEntity.ExecuteStoreCommand 
    ("UPDATE items SET itemstatus = 'some status' WHERE id = {0}", new object[] { 123 }); 

ACTUALIZACIÓN - para EF 6,0

dataEntity.Database.ExecuteSqlCommand 
     ("UPDATE items SET itemstatus = 'some status' WHERE id = {0}", new object[] { 123 }); 
+6

¿por qué reduciría esta respuesta sin dejar ningún comentario? Esta sugerencia aborda las preguntas originales de los autores. – barrypicker

+11

'ExecuteStoreCommand' no es realmente una forma EF de hacer esto, solo está usando el' DbConnection' contenido dentro del 'DbContext' para ejecutar un comando. No es una base de datos independiente, y mucho menos persistente (por ejemplo, este ejemplo se bloqueará si OP cambia a XML). –

+7

@ just.another.programmer - con gran poder viene una gran responsabilidad. – barrypicker

6

Si el DataItem tiene campos EF validar previamente (como campos no anulables), tendremos que desactivar que la validación de este contexto:

DataItem itemToUpdate = new DataItem { Id = id, Itemstatus = newStatus }; 
dataEntity.Entry(itemToUpdate).Property(x => x.Itemstatus).IsModified = true; 
dataEntity.Configuration.ValidateOnSaveEnabled = false; 
dataEntity.SaveChanges(); 
//dataEntity.Configuration.ValidateOnSaveEnabled = true; 

De lo contrario, puede intentar satisfacer la prevalidación y aún así sólo actualizar la columna simple:

DataItem itemToUpdate = new DataItem 
{ 
    Id = id, 
    Itemstatus = newStatus, 
    NonNullableColumn = "this value is disregarded - the db original will remain" 
}; 
dataEntity.Entry(itemToUpdate).Property(x => x.Itemstatus).IsModified = true; 
dataEntity.SaveChanges(); 

Suponiendo dataEntity es un System.Data.Entity.DbContext

puede verificar º e consulta genera sumando esto a la DbContext:

/*dataEntity.*/Database.Log = m => System.Diagnostics.Debug.Write(m); 
3

El código:

ExampleEntity exampleEntity = dbcontext.ExampleEntities.Attach(new ExampleEntity { Id = 1 }); 
exampleEntity.ExampleProperty = "abc"; 
dbcontext.Entry<ExampleEntity>(exampleEntity).Property(ee => ee.ExampleProperty).IsModified = true; 
dbcontext.Configuration.ValidateOnSaveEnabled = false; 
dbcontext.SaveChanges(); 

El resultado TSQL:

exec sp_executesql N'UPDATE [dbo].[ExampleEntities] 
SET [ExampleProperty ] = @0 
WHERE ([Id] = @1) 
',N'@0 nvarchar(32),@1 bigint',@0='abc',@1=1 

Nota:

El "IsModified = true" línea, es necesario porque cuando crea el nuevo objeto ExampleEntity (solo con la propiedad Id rellena) todas las demás propiedades tienen sus valores predeterminados (0, nulo, etc.). Si desea actualizar el DB con un "valor predeterminado", el marco de la entidad no detectará el cambio y, a continuación, DB no se actualizará.

En el ejemplo:

exampleEntity.ExampleProperty = null; 

no funcionará sin la línea "IsModified = true", debido a que el ExampleProperty propiedad, ya es nulo cuando se creó el objeto ExampleEntity vacío, que tiene que decir a EF que este la columna debe actualizarse, y este es el propósito de esta línea.

Cuestiones relacionadas