web-dev-qa-db-ja.com

エンティティフレームワークでGUID)のNewId()を設定する方法

私はasp.netmvc4サンプルを作成しています。これでは、データコンテキストのサンプルテーブルにGUIDとしてId列を作成しました。

_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パス00000000-0000-0000-0000-000000000000。

newid()GUIDに設定する方法と、どこに設定する必要があるか。

12
user2285613

IDタイプにはlongを使用することをお勧めします。これは「正しく機能」し、GUIDよりもパフォーマンスが向上します。ただし、GUIDを使用する場合は、 Sequential GUID を使用して、コンストラクターで設定する必要があります。また、IDを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);
        }
    }
13
Paul

これは、属性を使用して実行することもできます。

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid AddressID { get; set; }
8
TombMedia

データベースへのNlogロギングで同じ問題が発生しました。私がしたことは、移行ファイルを意図的に開くことであり、次の変更を行いました

_CreateTable(
"dbo.Samples",
c => new
{
     ID = c.Guid(nullable: false,identity:true),
     FirstName = c.String(nullable: false)
})
.PrimaryKey(t => t.ID);
_

アイデンティティパラメータは、実際にはdefaultvaluenewsequentialid()としてテーブルに作成しました。

5
Joy

これが良い考えであるかどうかにかかわらず、周りの政治を無視する場合、 @ TombMedia による答えがあなたが探しているものである可能性が最も高いです。

ただし、既存のテーブルに新しい列を追加する必要があり、フィールドがnull許容ではないためにデフォルト値に使用されるnewId()を指定する場合は、移行クラスでこれを使用します。

AddColumn(
    "dbo.Samples",
    "UUID", 
    c => c.Guid(nullable: false, defaultValueSql: "newId()")
);

注:これはEF6に関連する古い質問であり、EF移行内でnewIdを使用する方法についての支援を探すときに上位にランク付けされるため、この回答が追加されました。

4
Chris Schaller

Paulの答えは正しいですが、SequentialGuidの実装は改善できます。 シーケンシャルGUIDのこの実装 より頻繁にインクリメントし、同じサーバー上で作成された場合に同じ番号を防ぎます。

リンク切れ を防ぐために、コード:

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;
    }
}
2
Alex Siepman

私はその質問がかなり古いことを知っています、しかし誰かがそのような問題を抱えているならば、私はそのような解決策を提案します:

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

新しいオブジェクトの作成時に、SQLデータベースからnewidを取得できます。私にとってはうまくいきます。 :)(しかし、それが良い習慣かどうかはわかりません)

使用方法:

var myNewGuidValue = GetNewId();
0
Monic

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サーバーが、独自のGUIDよりも優れた順次GUIDを生成する責任を負うようになります。

シーケンシャルギッドを使用することのデメリットを望まない場合は、代わりに「newid()」を使用できます。

0
user5580884