Domanda

C'è un modo per implementare la strategia di identità del pettine GUID per gli oggetti nel nuovo quadro di entità 4.1 utilizzando il design Codefirst?Pensavo di impostare il StoreGeneratedPattern funzionerebbe, ma mi dà ancora guidali normali.

È stato utile?

Soluzione

Immagino che stia utilizzando SQL Server come database.Questo è un bell'esempio di incoerenza tra diversi strumenti MS.Il team di SQL Server non si consiglia di utilizzare newid() come valore predefinito per le colonne di UNIQUEIDENTIFIER e il team ADO.NET lo usano se si specifica la proprietà Guid come autogenerato nel database.Dovrebbero usare invece newsequentialid()!

Se si desidera guidamenti sequenziali generati dal database è necessario modificare la tabella generata ed è davvero complesso perché è necessario trovare il vincolo predefinito autogenerato, rilasciarlo e creare un nuovo vincolo.Tutto ciò può essere fatto in Inizializzatore di database personalizzato.Qui hai il mio codice di esempio:

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);
    }
}
.

Altri suggerimenti

Perché preoccuparsi dei valori predefiniti per le colonne GUID nel database del database?Perché non solo generare il GUID sul cliente come qualsiasi altro valore.Ciò richiede un metodo nel tuo codice client che genererà GUIDS a pettine:

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 );
}
.

Uno dei vantaggi del GUID è specificamente che è possibile generarli sul client senza un viaggio di andata e ritorno al database.

La risposta più semplice

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; }
}
.

Questo presuppone che tu abbia il set di tabelle del database con il valore predefinito di newsequentialid() che nel mio caso è gestito da migrazioni fluentmigrator.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top