Есть ли способ реализовать стратегию идентификации Guid COMB для объектов в новой Entity Framework 4.1 с использованием дизайна CodeFirst? Я думал, что установка StoreGeneratedPattern
сработает, но она по-прежнему дает мне обычные GUID.
Стратегия GUID COMB в EF
Ответы (3)
Я предполагаю, что вы используете SQL-сервер в качестве базы данных. Это хороший пример несогласованности между различными инструментами MS. Команда SQL Server не рекомендует использовать newid()
в качестве значения по умолчанию для столбцов UNIQUEIDENTIFIER
, а группа ADO.NET использует его, если вы укажете свойство Guid
как автоматически сгенерированное в базе данных. Вместо этого они должны использовать newsequentialid()
!
Если вы хотите, чтобы последовательные Guids генерировались базой данных, вы должны изменить сгенерированную таблицу, и это действительно сложно, потому что вы должны найти автоматически сгенерированное ограничение по умолчанию, удалить его и создать новое ограничение. Все это можно сделать в пользовательском инициализаторе базы данных. Вот мой пример кода:
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);
}
}
Зачем вообще беспокоиться о значениях по умолчанию для столбцов Guid в базе данных? Почему бы просто не сгенерировать Guid на клиенте, как и любое другое значение. Для этого требуется, чтобы в вашем клиентском коде был метод, который будет генерировать 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 );
}
Одним из преимуществ Guid является именно то, что вы можете генерировать их на клиенте без обращения к базе данных.
Самый простой ответ
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; }
}
Это предполагает, что у вас есть таблица базы данных со значением по умолчанию newsequentialid()
, которым в моем случае управляет миграция FluentMigrator.
newsequentialid()
, действительно выходит за рамки этого вопроса и становится общей проблемой схемы sql.
- person Chris Marisic; 12.12.2012