17

現在、Entity Framework 5 を使用して ASP.Net MVC 4 アプリケーションに取り組んでいます。初期開発段階では CodeFirst を使用しました。ただし、自動移行を無効にし、SSMS を使用して POCO を直接使用して新しいテーブルを設計しています。すべてがうまくいっています。

最近、プロダクションで奇妙な問題を特定しました。最初に設計されたテーブルの 1 つのレコードは、自動インクリメント ID 値を 900 を超える数字でスキップしました。これは、過去 3 か月間に 3 回発生しました。アプリケーションをローカルでデバッグしましたが、再現できませんでした。観察されるパターンや傾向はありません。

モデル:

public class Enquiry
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public Int64 EnquiryId { get; set; }

    [Required]
    public int UserId { get; set; }

    [Required]
    public byte Bid { get; set; }

    ...

    [Required]
    public DateTime Created { get; set; }

    [Required]
    public DateTime Modified { get; set; }
}

public class EnquiryDetail
{
    [Key]
    public Int64 EnquiryId { get; set; }

    [Required]
    public int CreditScore { get; set; }

    [Required]
    public byte BidMode { get; set; }

    public virtual Enquiry Enquiry { get; set; }
}

DB コンテキスト:

public class EscrowDb : DbContext
{

    public EscrowDb()
        : base("name=DefaultConnection")
    {

    }
    public DbSet<Enquiry> Enquiries { get; set; }
    public DbSet<EnquiryDetail> EnquiryDetails { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Entity<EnquiryDetail>()
            .HasRequired<Enquiry>(ed => ed.Enquiry)
            .WithRequiredDependent(e => e.EnquiryDetail);
    }
}

コントローラ:

[Authorize]
public class EnquiryController : Controller
{
    private EscrowDb _db = new EscrowDb();

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(EnquiryViewModel core)
    {
       var enquiry = new Enquiry();
       // Some code to set properties using passed ViewModel
       ...

       var enquiryDetail = new EnquiryDetail();
       // Some code to set properties using passed ViewModel
       ...

       enquiry.EnquiryDetail = enquiryDetail;

       _db.Enquiries.Add(enquiry);
       _db.SaveChanges();
    }
}

このコードはすべて、ほぼ 1000 の数字の大きなギャップによって散発的にスキップされる ID 値を除いて、これまでのところ正常に機能しています。

誰もそのような問題に遭遇しましたか? あなたの考えを共有してください。

4

4 に答える 4

19

これらのギャップを解消する必要がある場合、ここでは運が悪いかもしれません。

新しいアプリケーションを開発/テストしているときに、この問題に遭遇しました。SQL Server 2012 について読んだ内容に基づいて、ここで sql azure で何が起こっているのかを直感的に理解しています。sql azure に関するドキュメントを見つけることができませんでした。

私が読んだことから、これはバグIMOとして出くわす機能です。Sql server 2012 では、Microsoft はシーケンスを作成する機能を追加しました。シーケンスは、1000 のブロックで使用された値を記録します。したがって、シーケンスが進行していたとしましょう... 1、2、3、4、5... その後、SQL サーバーが再起動します。シーケンスは、ブロック 1-1000 が既に使用されているという事実を既に保存しているため、次の 1000 にジャンプします.... したがって、次の値は 1001、1002、1003、1004 です....これにより、のパフォーマンスが向上しますシーケンスを使用するときに挿入しますが、異常なギャップが発生する可能性があります。あなたのシーケンスにはこれに対する解決策があります。シーケンスを指定するときは、「NOCACHE」パラメーターを追加して、一度に 1000 のブロックを保存しないようにします。詳細なドキュメントについては、こちらを参照してください。

これが問題になるのは、この同じパラダイムを使用するように ID 列が変更されたように見えることです。したがって、サーバー、またはこの場合は SQL azure インスタンスが再起動すると、ID 列に大きなギャップ (1000 秒) が発生する可能性があります。これは、大きなブロックが "使用済み" としてキャッシュされているためです。SQL Server 2012 にはこれに対する解決策があります。スタートアップ フラグ t272 を指定して、ID を古い SQL Server 2008 r2 パラダイムを使用するように戻すことができます。問題は、SQL Azure でこれを指定する方法を知らない (できないかもしれない) ことです。ドキュメントが見つかりません。 SQL Server 2012 の詳細については、このスレッドを参照してください。

msdn で ID のドキュメントを確認してください。具体的には、「サーバーの再起動またはその他の障害後の連続値」セクション。これがそれが言うことです:

サーバーの再起動またはその他の障害後の連続した値– SQL Server は、パフォーマンス上の理由から ID 値をキャッシュする場合があり、割り当てられた値の一部は、データベースの障害またはサーバーの再起動中に失われる可能性があります。これにより、挿入時に ID 値にギャップが生じる可能性があります。ギャップが受け入れられない場合、アプリケーションは NOCACHE オプションを指定してシーケンス ジェネレーターを使用するか、独自のメカニズムを使用してキー値を生成する必要があります。

したがって、連続した値が必要な場合は、ID 列に頼るのではなく、nocache でシーケンスを指定してみてください。これを自分で試したことはありませんが、これをエンティティ フレームワークで動作させるのに問題があるようです。

これがあまり役に立たない場合は申し訳ありませんが、少なくともあなたが経験していることに関する情報です.

于 2013-07-10T14:00:06.967 に答える
1

トリガー アプローチを使用した再シードを試してください。これにより、その使用例が解決され、そのリンクでさらに多くのウォークアラウンドが表示されるはずです。

USE [TEST]

CREATE TABLE TEST(ID INT IDENTITY(1,1),VAL VARCHAR(10))

CREATE TRIGGER TGR_TEST_IDENTITY ON TEST
FOR INSERT
AS
DECLARE @RESEEDVAL INT
SELECT @RESEEDVAL = MAX(ID) FROM TEST
DBCC CHECKIDENT('TEST', RESEED, @RESEEDVAL)

INSERT INTO TEST(VAL)VALUES('a')

SELECT * FROM TEST

「DBCC CHECKIDENT」は Azure でサポートされていないため、このリンクのアプローチを使用できるようになりました 。そのリンクでは、いくつかの回避策があります。

  1. SqlAzure の自動キーを使用する場合は、GUID をキーとして使用します
  2. 私の場合のような整数キーがレコードを挿入して戻って削除し、identity_insert XXXTableをオンにしてIDをオフにすることにより、正しいキーで再挿入する場合-これは基本的にIDENTITYをオフにします

そして、正しいキーを使用して挿入が終わったら、再びアイデンティティをオンに戻します

set identity_insert XXXTable off -- これは基本的に IDENTITY をオンにします

注: これは大量の挿入リクエストを受信して​​いるテーブルには適していませんが、一時的な方法を探している人には役立つかもしれません

于 2014-05-22T09:52:40.257 に答える
0

SQL Azure に対する TF 272 の回避策はないようです。2 つのテーブルの問題 (999 と 1000 のギャップ) に気付き、2 つのテーブルを調べて挿入されたレコードをチェックする前に、セキュリティ違反だと思いました。詳細については、この MS TechNet ディスカッションの最後の項目を参照してください。ちょっと安心ですが、機能というよりはバグのように見えます。

于 2013-12-25T17:19:04.833 に答える