entity-framework - tutorial - mvc 5 entity framework relationships
Código de Entity Framework Primero, usar Guid como identidad con otra columna de identidad (1)
aka ¿Cómo podemos crear múltiples columnas de identidad en Code First?
Debido al rendimiento del clúster, una recomendación común es usar una columna entera autoincrementada en lugar de un GUID creado con newid()
.
Para declarar una columna como autoincrement, debe especificarla con la Anotación [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
.
Pero, solo puedes tener una identidad en una tabla.
Entonces comenzando con un modelo base como:
public abstract class ModelBase {
// the primary key
public virtual Guid Id { get; set; }
// a unique autoincrementing key
public virtual int ClusterId { get; set; }
}
¿Cómo lo configuramos para que:
- Guid es generado automáticamente por la base de datos, no el código
-
ClusterId
está autoincrementado - El código de Entity Framework First no arroja todo tipo de errores como:
- Las modificaciones a tablas en las que una columna de clave principal tiene la propiedad ''StoreGeneratedPattern'' establecida en ''Computada'' no son compatibles. Use el patrón ''Identidad'' en su lugar.
Para su información , si desea generarlo automáticamente en el código, puede omitir la anotación en el campo Id y hacer algo como:
public abstract class AbstractContext : DbContext {
/// <summary>
/// Custom processing when saving entities in changetracker
/// </summary>
/// <returns></returns>
public override int SaveChanges()
{
// recommended to explicitly set New Guid for appropriate entities -- http://msdn.microsoft.com/en-us/library/dd283139.aspx
foreach (var entry in ChangeTracker.Entries<ModelBase>().Where(e => e.State == EntityState.Added) ) {
// only generate if property isn''t identity...
Type t = entry.Entity.GetType();
var info = t.GetProperty("Id").GetCustomAttributes(
typeof(DatabaseGeneratedAttribute), true).Cast<DatabaseGeneratedAttribute>().Single();
if (info.DatabaseGeneratedOption != DatabaseGeneratedOption.Identity) {
entry.Entity.Id = Guid.NewGuid(); // now we make it
}
}
return base.SaveChanges();
}
}
Esto terminó funcionando para mí, Entity Framework 5.
- Desactivar migraciones automáticas
- Migra para crear la tabla inicial, sin lujos
Declarar el
ClusterId
como identidad (anotación)[DatabaseGenerated(DatabaseGeneratedOption.Identity)] public override int ClusterId { get; set; }
Emigrar
Declare el
Id
propiedad pk como identidad después de que se haya actualizado el otro[DatabaseGenerated(DatabaseGeneratedOption.Identity)] public override Guid Id { get; set; }
- bonificación : EF parece suponer que
Id
es la clave principal, por lo que no necesita[Key, Required]
- bonificación : EF parece suponer que
Cree el código de migración como
add-migration TrickEfIntoAutogeneratingMultipleColumns
- En el método
Up()
, en la instrucciónAlterColumn
,AlterColumn
a la base de datos quedefaultSqlValue
el GUID declarandodefaultSqlValue
-
AlterColumn(theTable, "Id", c => c.Guid(nullable: false, identity: true, defaultValueSql: "newid()"));
-
- Emigrar
Esto parece "engañar" a EF, en el sentido de que asume que ambas columnas son identidades y reacciona en consecuencia. Durante la migración, intenta hacer que otra columna sea una identidad, pero al parecer no le importa cuando eso falla silenciosamente: usted termina con una marcada como Identidad y la otra con un valor predeterminado.
Durante el funcionamiento normal del código, cuando EF pasa por los pasos SaveChanges / ChangeTracking, porque ve la propiedad Id
como una Identidad, hace todo su "asignar clave temporal" , de modo que no está tratando de usar el valor 0000000 predeterminado ... y en su lugar permite que la base de datos la genere utilizando la función de valor por defecto que especificó.
(Hubiera pensado anotar este campo como Computed
hubiera logrado lo mismo, pero ... los errores que mencioné en la pregunta ... boo ...)
Y, como el campo ClusterId
también es una Identidad en el código, y realmente es una Identidad en la base de datos, también se autoincrementa.