c# - primary - entity framework guid auto generated
Estrategia GUID COMB en EF (3)
La respuesta más simple
public class User
{
public User(Guid? id = null, DateTime? created = null)
{
if (id != null)
Id = id;
if (created != null)
Created = created;
}
public User()
{
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime? Created { get; internal set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid? Id { get; internal set; }
}
Esto supone que tiene su tabla de base de datos establecida con el valor predeterminado de newsequentialid()
que en mi caso es administrado por las migraciones de FluentMigrator.
¿Hay alguna forma de implementar la estrategia de identidad Guid COMB para objetos en el nuevo Entity Framework 4.1 utilizando el diseño CodeFirst? Pensé que configurar StoreGeneratedPattern
funcionaría, pero aún así me da GUID normales.
¿Por qué preocuparse por los valores predeterminados de las columnas Guid en la base de datos? ¿Por qué no generar el Guid en el cliente como cualquier otro valor? Eso requiere que tengas un método en tu código de cliente que genere guiones similares a COMB:
public static Guid NewGuid()
{
var guidBinary = new byte[16];
Array.Copy( Guid.NewGuid().ToByteArray(), 0, guidBinary, 0, 8 );
Array.Copy( BitConverter.GetBytes( DateTime.Now.Ticks ), 0, guidBinary, 8, 8 );
return new Guid( guidBinary );
}
Una de las ventajas del Guid es específicamente que puede generarlos en el cliente sin un viaje de ida y vuelta a la base de datos.
Supongo que está utilizando SQL Server como su base de datos. Este es un buen ejemplo de inconsistencia entre las diferentes herramientas de MS. El equipo del servidor SQL no recomienda usar newid()
como valor predeterminado para UNIQUEIDENTIFIER
columnas UNIQUEIDENTIFIER
y el equipo de ADO.NET lo usa si especifica la propiedad Guid
como autogenerada en la base de datos. ¡Deberían usar newsequentialid()
lugar!
Si desea Guiones secuenciales generados por la base de datos, debe modificar la tabla generada y es realmente compleja porque debe encontrar la restricción predeterminada autogenerada, soltarla y crear una nueva restricción. Todo esto se puede hacer en el inicializador de base de datos personalizado. Aquí tienes mi código de muestra:
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new CustomInitializer());
using (var context = new Context())
{
context.TestEntities.Add(new TestEntity() { Name = "A" });
context.TestEntities.Add(new TestEntity() { Name = "B" });
context.SaveChanges();
}
}
}
public class CustomInitializer : DropCreateDatabaseAlways<Context>
{
protected override void Seed(Context context)
{
base.Seed(context);
context.Database.ExecuteSqlCommand(@"
DECLARE @Name VARCHAR(100)
SELECT @Name = O.Name FROM sys.objects AS O
INNER JOIN sys.tables AS T ON O.parent_object_id = T.object_id
WHERE O.type_desc LIKE ''DEFAULT_CONSTRAINT''
AND O.Name LIKE ''DF__TestEntities__Id__%''
AND T.Name = ''TestEntities''
DECLARE @Sql NVARCHAR(2000) = ''ALTER TABLE TestEntities DROP Constraint '' + @Name
EXEC sp_executesql @Sql
ALTER TABLE TestEntities
ADD CONSTRAINT IdDef DEFAULT NEWSEQUENTIALID() FOR Id");
}
}
public class TestEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public class Context : DbContext
{
public DbSet<TestEntity> TestEntities { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<TestEntity>()
.Property(e => e.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}