2012-03-19 17 views
5

IDbSetExtensions.AddOrUpdate está destinado a ayudar a escribir código que funciona igual si la base de datos está vacía o llena. Pero vincular objetos necesita un código diferente. Cuando la base de datos está vacía, los objetos aún no tienen ID y los vincula mediante la asignación de la propiedad de navegación. Sin embargo, cuando los objetos ya existen, las propiedades de navegación no funcionan y debe establecer las claves foráneas directamente. Las propiedades de navegación funcionan para proxies en ambos casos, a costa de perder POCO. Editar: En realidad, los proxies no funcionan cuando ambas entidades son antiguas.IDbSetExtensions.AddOrUpdate y relaciones

accidentes de esta muestra en el segundo SaveChanges llaman, cuando se trata de establecer EF CountryId a 0:

public class Country 
{ 
    public virtual int ID { get; set; } 
    public virtual string Name { get; set; } 
} 

public class Person 
{ 
    public virtual int ID { get; set; } 
    public virtual string Name { get; set; } 

    public virtual int CountryID { get; set; } 
    public virtual Country Country { get; set; } 
} 

public class Context : DbContext 
{ 
    public DbSet<Person> Person { get; set; } 
    public DbSet<Country> Country { get; set; } 
} 

class Program 
{ 
    static void Foo() 
    { 
     using (var db = new Context()) 
     { 
      //var c = new Country(); 
      var c = db.Country.Create(); 
      c.Name = "usa"; 
      db.Country.AddOrUpdate(x => x.Name, c); 

      //var p = new Person(); 
      var p = db.Person.Create(); 
      p.Name = "billg"; 
      p.Country = c; 
      db.Person.AddOrUpdate(x => x.Name, p); 

      db.SaveChanges(); 
     } 
    } 
    static void Main() 
    { 
     Database.SetInitializer<Context>(new DropCreateDatabaseAlways<Context>()); 
     Foo(); 
     Foo(); 
    } 
} 

¿Cómo se usa AddOrUpdate?

+1

le recomiendo que lo leas http://thedatafarm.com/blog/data-access/take-care-with-ef-4- 3-addorupdate-method/ –

Respuesta

9

IDbSetExtensions.AddOrUpdate está destinado a ayudar a escribir código que funciona igual si la base de datos está vacía o llena.

AddOrUpdate está destinado a ser utilizado solo en Seed método de primer código de migraciones. No se supone que se use en código normal porque tiene una gran sobrecarga y algunas limitaciones. Overhead es una consulta adicional a la base de datos y la reflexión. La limitación es que solo verifica la entidad principal que está pasando, pero no sus relaciones. Cada relación se supone que debe ser manejado por separado llamada a AddOrUpdate:

static void Foo() 
{ 
    using (var db = new Context()) 
    { 
     var c = new Country() {Name = "abc"}; 
     db.Country.AddOrUpdate(x => x.Name, c); 

     var p = new Person() 
     { 
      Name = "me", 
      CountryID = c.ID, 
      Country = c 
     }; 

     db.Person.AddOrUpdate(x => x.Name, p); 
     db.SaveChanges(); 
    } 
} 
+1

Acorté mi código para pegarlo aquí. Mi aplicación solo usa AddOrUpdate en una anulación de DbMigrationsConfiguration.Seed. Su muestra funciona, pero me siento incómodo al asignar tanto Country como CountryID. ¿Recomiendas asignar siempre ambos? Mi aplicación utiliza claves compuestas y es más fácil, más clara y menos propensa a errores asignar solo la propiedad de navegación. –

+0

@BrunoMartinez AddOrUpdate *** no *** configurará los valores de clave foránea en los que se basa la propiedad de navegación (y la base de datos), incluso si esa entidad ya ha sido 'añadida o actualizada' o consultada directamente (y EF debería ser capaz de arreglar la relación). Realísticamente, *** solo necesitas configurar el FK ***, a menos que necesites navegar las relaciones más adelante en la semilla. Además, si desea usar la relación como parte de 'identifierExpression', debe usar FK Id, ya que debe ser un valor primitivo o enum y la propiedad asignada a una columna; no se pueden usar otras entidades. – JoeBrockhaus

+0

RE: * "es más fácil, más claro y menos propenso a errores asignar solo la propiedad de navegación." * Aconsejaría agregar algunos métodos de extensión para sus entidades a 'AddRelatedEntity (entidad RelatedEntity) {..}' o simplemente usar el nativo ' Los métodos de DbSet' básicamente escriben su propio 'AddOrUpdate()'. Es * frustrante que esta superficie API no siga las mismas convenciones que el resto de las operaciones DbContext/DbSet. ¯ \\ _ (ツ) _/¯ – JoeBrockhaus