Как установить NewId() для GUID в инфраструктуре сущности
Я создаю образец asp.net mvc4. В этом я создал столбец Идентификатор в качестве идентификатора GUID в таблице примеров datacontext.
public class Sample
{
[Required]
public Guid ID { get; set; }
[Required]
public string FirstName { get; set; }
}
Это таблица сущностей
CreateTable(
"dbo.Samples",
c => new
{
ID = c.Guid(nullable: false),
FirstName = c.String(nullable: false)
})
.PrimaryKey(t => t.ID);
Id pass 00000000-0000-0000-0000-000000000000.
Как установить newid()
в GUID
и где я должен установить.
Ответы
Ответ 1
Я бы рекомендовал использовать long
для вашего типа идентификатора. Он "просто работает" и имеет некоторые улучшения производительности по сравнению с GUID. Но если вы хотите использовать GUID, вы должны использовать Sequential GUID и установить его в конструкторе. Я также хотел бы установить идентификатор private
:
public class Sample
{
public Sample() {
ID = GuidComb.Generate();
}
[Required]
public Guid ID { get; private set; }
[Required]
public string FirstName { get; set; }
}
Последовательный GUID
public static class GuidComb
{
public static Guid Generate()
{
var buffer = Guid.NewGuid().ToByteArray();
var time = new DateTime(0x76c, 1, 1);
var now = DateTime.Now;
var span = new TimeSpan(now.Ticks - time.Ticks);
var timeOfDay = now.TimeOfDay;
var bytes = BitConverter.GetBytes(span.Days);
var array = BitConverter.GetBytes(
(long)(timeOfDay.TotalMilliseconds / 3.333333));
Array.Reverse(bytes);
Array.Reverse(array);
Array.Copy(bytes, bytes.Length - 2, buffer, buffer.Length - 6, 2);
Array.Copy(array, array.Length - 4, buffer, buffer.Length - 4, 4);
return new Guid(buffer);
}
}
Ответ 2
Это также можно сделать с помощью атрибутов:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid AddressID { get; set; }
Ответ 3
Я столкнулся с той же проблемой, когда Nlog регистрировался в базе данных. То, что я сделал, - это намеренно открыть файл миграции и внес следующие изменения.
CreateTable(
"dbo.Samples",
c => new
{
ID = c.Guid(nullable: false,identity:true),
FirstName = c.String(nullable: false)
})
.PrimaryKey(t => t.ID);
идентификационный параметр фактически создал таблицу с defaultvalue
как newsequentialid()
в таблице.
Ответ 4
Ответ Павла прав, но реализация Sequential Guid может быть улучшена. Эта реализация последовательного guid увеличивается чаще и предотвращает одинаковые номера, если они созданы на одном сервере.
Чтобы предотвратить ссылку rot, код:
public class SequentialGuid
{
public DateTime SequenceStartDate { get; private set; }
public DateTime SequenceEndDate { get; private set; }
private const int NumberOfBytes = 6;
private const int PermutationsOfAByte = 256;
private readonly long _maximumPermutations = (long)Math.Pow(PermutationsOfAByte, NumberOfBytes);
private long _lastSequence;
public SequentialGuid(DateTime sequenceStartDate, DateTime sequenceEndDate)
{
SequenceStartDate = sequenceStartDate;
SequenceEndDate = sequenceEndDate;
}
public SequentialGuid()
: this(new DateTime(2011, 10, 15), new DateTime(2100, 1, 1))
{
}
private static readonly Lazy<SequentialGuid> InstanceField = new Lazy<SequentialGuid>(() => new SequentialGuid());
internal static SequentialGuid Instance
{
get
{
return InstanceField.Value;
}
}
public static Guid NewGuid()
{
return Instance.GetGuid();
}
public TimeSpan TimePerSequence
{
get
{
var ticksPerSequence = TotalPeriod.Ticks / _maximumPermutations;
var result = new TimeSpan(ticksPerSequence);
return result;
}
}
public TimeSpan TotalPeriod
{
get
{
var result = SequenceEndDate - SequenceStartDate;
return result;
}
}
private long GetCurrentSequence(DateTime value)
{
var ticksUntilNow = value.Ticks - SequenceStartDate.Ticks;
var result = ((decimal)ticksUntilNow / TotalPeriod.Ticks * _maximumPermutations - 1);
return (long)result;
}
public Guid GetGuid()
{
return GetGuid(DateTime.Now);
}
private readonly object _synchronizationObject = new object();
internal Guid GetGuid(DateTime now)
{
if (now < SequenceStartDate || now > SequenceEndDate)
{
return Guid.NewGuid(); // Outside the range, use regular Guid
}
var sequence = GetCurrentSequence(now);
return GetGuid(sequence);
}
internal Guid GetGuid(long sequence)
{
lock (_synchronizationObject)
{
if (sequence <= _lastSequence)
{
// Prevent double sequence on same server
sequence = _lastSequence + 1;
}
_lastSequence = sequence;
}
var sequenceBytes = GetSequenceBytes(sequence);
var guidBytes = GetGuidBytes();
var totalBytes = guidBytes.Concat(sequenceBytes).ToArray();
var result = new Guid(totalBytes);
return result;
}
private IEnumerable<byte> GetSequenceBytes(long sequence)
{
var sequenceBytes = BitConverter.GetBytes(sequence);
var sequenceBytesLongEnough = sequenceBytes.Concat(new byte[NumberOfBytes]);
var result = sequenceBytesLongEnough.Take(NumberOfBytes).Reverse();
return result;
}
private IEnumerable<byte> GetGuidBytes()
{
var result = Guid.NewGuid().ToByteArray().Take(10).ToArray();
return result;
}
}
Ответ 5
Я знаю, что вопрос довольно старый, но если у кого-то есть такая проблема, я предлагаю такое решение:
protected Guid GetNewId()
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["YourConnectionString"].ConnectionString);
var query = "select newid()";
conn.Open();
SqlCommand com = new SqlCommand(query, conn);
var guid = new Guid(com.ExecuteScalar().ToString());
conn.Close();
return guid;
}
Вы можете получить newid из базы данных SQL при создании нового объекта. Для меня это работает.:) (но я не знаю, что это хорошая практика)
Как это использовать:
var myNewGuidValue = GetNewId();
Ответ 6
Если мы игнорируем политику вокруг, если это хорошая идея или нет, то ответ @TombMedia, скорее всего, то, что вы ищете.
Однако, если вам нужно добавить новый столбец в существующую таблицу и указать, что newId() будет использоваться в качестве значения по умолчанию, так как поле не может быть пустым, используйте это в своем классе миграции:
AddColumn(
"dbo.Samples",
"UUID",
c => c.Guid(nullable: false, defaultValueSql: "newId()")
);
Примечание: это старый вопрос, который все еще актуален в EF6 и занимает высокое место при поиске помощи в том, как использовать newId в миграциях EF, поэтому этот ответ был добавлен.
Ответ 7
При использовании Entity Framework Core 2.1.1 я использую:
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid UserId { get; set; }
Затем в миграции добавьте параметр defaultValueSql, как показано ниже:
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
UserId = table.Column<Guid>(nullable: false, defaultValueSql: "newsequentialid()"),
DisplayName = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.UserId);
});
Это гарантирует, что сервер sql отвечает за генерацию последовательного руководства, которое будет лучше, чем собственное.
Если вам не нужны недостатки использования последовательных направляющих, вы можете вместо этого использовать "newid()".