10

エラー:

未処理の例外: System.Data.SqlClient.SqlException: テーブル 'PrivateMakeUpLessons' に名前 'IX_ID' のインデックスまたは統計が既に存在するため、操作は失敗しました。

モデル (簡素化、デバッグ用に別のテスト プロジェクトでビルド):

public abstract class Lesson
{
    public Guid ID { get; set; }
    public string Room { get; set; }
    public TimeSpan Time { get; set; }
    public int Duration { get; set; }
}

public abstract class RecurringLesson : Lesson
{
    public int DayOfWeek { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public string Frequency { get; set; }
}

public class PrivateLesson : RecurringLesson
{
    public string Student { get; set; }
    public string Teacher { get; set; }
    public virtual ICollection<Cancellation> Cancellations { get; set; }
}

public class Cancellation
{
    public Guid ID { get; set; }
    public DateTime Date { get; set; }
    public virtual PrivateLesson Lesson { get; set; }
    public virtual MakeUpLesson MakeUpLesson { get; set; }
}

public class MakeUpLesson : Lesson
{
    public DateTime Date { get; set; }
    public string Teacher { get; set; }
    public virtual Cancellation Cancellation { get; set; }
}

構成:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Lesson>().ToTable("Lessons");
    modelBuilder.Entity<RecurringLesson>().ToTable("RecurringLessons");
    modelBuilder.Entity<PrivateLesson>().ToTable("PrivateLessons");
    modelBuilder.Entity<MakeUpLesson>().ToTable("PrivateMakeUpLessons");

    modelBuilder.Entity<Cancellation>()
        .HasOptional(x => x.MakeUpLesson)
        .WithRequired(x => x.Cancellation);

    base.OnModelCreating(modelBuilder);
}

:

これは EF 4.2 で正常に機能しました。私のモデルに何か問題がありますか? 実際のモデルはもっと複雑なので、すべてのクラスを抽象化しています。また、既存のデータベースに対して作業しているため、Table-Per-Type 継承を使用する必要があります。

の関係を 1 から 0..1 から 0..1 から 0..1 に変更すると、Cancellation機能PrivateMakeUpLessonします。PrivateMakeUpLessonなしでは を持てないため、これは望ましくありませんCancellation

また、PrivateMakeUpLesson継承しないようにLessonしても機能しますが、これは教訓であり、既存のビジネス ロジックについてはそのままにしておく必要があります。

ガイダンスをいただければ幸いです。ありがとうございました!

編集

バウンティを開始します。最初のコードのインデックス生成に関して、EF 4.2 と EF 4.3 の間で何が変更されたかについてのドキュメントが見つかりません。EF 4.3 がより多くのインデックスを作成し、命名スキームが変更されたことは明らかですが、EF にバグがあるかどうか、またはモデルまたは流暢な API 構成に根本的な問題があるかどうかを知りたいです。

4

5 に答える 5

9

EF 4.3 の時点で、データベースの作成中に freign キー列にインデックスが追加されます。インデックスが複数回作成されるバグがあります。これは、将来の EF リリースで修正される予定です。

それまでは、データベース初期化子 (またはメソッド)の代わりにMigrationsを使用してデータベースを作成することで、この問題を回避できます。Database.Create()

最初の移行を生成したら、への冗長な呼び出しを削除する必要がありますIndex()

CreateTable(
    "dbo.PrivateMakeUpLessons",
    c => new
        {
            ID = c.Guid(nullable: false),
            ...
        })
    .PrimaryKey(t => t.ID)
    .ForeignKey("dbo.Lessons", t => t.ID)
    .ForeignKey("dbo.Cancellations", t => t.ID)
    .Index(t => t.ID)
    .Index(t => t.ID); // <-- Remove this

実行時にデータベースの作成を続行するには、MigrateDatabaseToLatestVersion初期化子を使用できます。

于 2012-05-14T22:33:48.067 に答える
5

私の意見では、これは明らかにバグです。

問題は、EF がまったくインデックスIX_IDを作成しないという観察から始まります。モデルを次のように削除すると...

public abstract class Lesson
{
    public Guid ID { get; set; }
}

public class RecurringLesson : Lesson
{
}

public class MyContext : DbContext
{
    public DbSet<Lesson> Lessons { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<RecurringLesson>().ToTable("RecurringLessons");
    }
}

...そして、EFにデータベーススキーマを作成させて、2つのテーブルを取得LessonsRecurringLessons、TPT継承マッピングに期待どおりにします。しかし、なぜテーブルに2つのインデックスを作成するのか疑問に思っていますRecurringLessons:

  • インデックスPK_RecurringLessons列を使用したインデックス (クラスタ化、一意)ID
  • 再度Index 列を使用したインデックスIX_ID(クラスター化されていない、一意ではない)ID

データベースが同じ列に 2 番目のインデックスを持つことに利点があるかどうかはわかりません。しかし、私の理解では、1) PK クラスター化インデックスで既にカバーされている同じ列にインデックスを作成すること、および 2)主キーである列に一意ではないインデックスを作成することは意味がありません。個性的。

さらに、1 対 1 の関係により、EF は、この関連付けの従属のテーブルにインデックスを作成しようとしますPrivateMakeUpLessons。(エンティティCancellation必要なため、従属 (プリンシパルではありません)ですMakeUpLesson。)

IDこのアソシエーションの外部キーです (1 対 1 の関係は常に Entity Framework の主キー アソシエーションで共有されるため、同時に主キーでもあります)。EF は明らかに常にリレーションシップの外部キーにインデックスを作成します。ただし、1 対多の関係の場合、FK 列は PK 列とは異なるため、これは問題になりません。1 対 1 の関係ではそうではありません: FK と PK は同じ (つまりID) であるため、EF はIX_ID、TPT 継承マッピング (これにより、データベースの観点からも 1 対 1 の関係)。

ここでも上記と同じ考慮事項が適用されます。テーブルPrivateMakeUpLessonsには、列 にクラスター化された PK インデックスがありますIDIX_IDなぜ同じ列に2 番目のインデックスが必要なのですか?

さらに、EF は、TPT 継承の名前でインデックスを作成する必要があることを確認していないようでIX_ID、データベース スキーマを作成するために DDL が送信されると、最終的にデータベースで例外が発生します。

EF 4.2 (およびそれ以前) はインデックス (PK インデックスを除く) をまったく作成しませんでした。これは EF 4.3 で導入され、特に FK 列のインデックスが導入されました。

回避策が見つかりませんでした。最悪の場合、データベース スキーマを手動で作成し、EF がそれを作成しようとしないようにする (= データベースの初期化を無効にする) 必要があります。最良の場合、FK インデックスの自動作成を無効にする方法がありますが、それが可能かどうかはわかりません。

バグ レポートは、http: //connect.microsoft.com/VisualStudioから送信できます。

または、EF 開発チームの誰かがここであなたの質問を見て、解決策を提供するかもしれません。

于 2012-05-11T12:29:47.063 に答える
2

以下に、おそらくうまくいかない 2 つのシナリオについて説明します。私の説明の詳細については、提供したリンクをクリックして詳細をお読みください。


まず
LessonRecurringLessonabstractクラスです (したがって、それを基本クラスとして使用する必要があります)。とエンティティ
のテーブルを作成しています。これにより、階層構造ごとのテーブルが作成されます。 簡単な説明ベース テーブル のクラスを作成すると、継承されたすべてのテーブルの列を含む 1 つの大きなテーブルが作成されます。したがって、 のすべてのプロパティと、継承された他のすべてのエンティティがテーブルに格納されます。EFも追加しますLessonRecurringLesson
PrivateLessonMakeUpLessonLessonsDiscriminator桁。この列のデフォルト値は、永続的なクラス名 (「PrivateLesson」や「MakeUpLesson」など) になります。その特定のエンティティに一致する (Discriminator 値に一致する) 列のみが、その特定の行で使用されます。

しかし、および
のような継承されたクラスもマッピングしています。これにより、クラスごとに 1 つのテーブルになるType構造ごとにテーブルを使用するように EF が強制されます。これにより、現在直面している競合が発生する可能性があります。PrivateLessonMakeUpLesson


2 番目
の例は、1 対 1 の関係 ( Cancellation -> MakeUpLesson) と1 対多の関係 ( Cancellation -> PrivateLesson)があることを示しています。これは、PrivateLessonとが両方とも (間接的に)最初に説明したシナリオと組み合わせてMakeUpLesson継承されているためです。エンティティごとのデータベース内の外部キー関係。(1 つはTable per hierarchy構造を使用し、もう 1 つはTable per Type構造を使用します)。Lesson

また、この投稿は、正しい 1 対 1 の定義を定義するのに役立ちます。


次の手順を実行して確認してください:
新しいテスト データベースを作成できるように、独自のテスト環境があることを前提としています。

1.Cancellationこのクラスのすべてのプロパティをコメントアウトして 、 との関係を削除します。

public class PrivateLesson : RecurringLesson
{
    public string Student { get; set; }
    public string Teacher { get; set; }
    //public virtual ICollection<Cancellation> Cancellations { get; set; }
}

public class Cancellation
{
    public Guid ID { get; set; }
    public DateTime Date { get; set; }
    //public virtual PrivateLesson Lesson { get; set; }
    //public virtual MakeUpLesson MakeUpLesson { get; set; }
}

public class MakeUpLesson : Lesson
{
    public DateTime Date { get; set; }
    public string Teacher { get; set; }
    //public virtual Cancellation Cancellation { get; set; }
}

そして、構成を削除します。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Lesson>().ToTable("Lessons");
    modelBuilder.Entity<RecurringLesson>().ToTable("RecurringLessons");
    modelBuilder.Entity<PrivateLesson>().ToTable("PrivateLessons");
    modelBuilder.Entity<MakeUpLesson>().ToTable("PrivateMakeUpLessons");

    //modelBuilder.Entity<Cancellation>()
    //    .HasOptional(x => x.MakeUpLesson)
    //    .WithRequired(x => x.Cancellation);

    base.OnModelCreating(modelBuilder);
}

2. 新しい空のデータベースを作成します
。 3. EF によって、この空のデータベースにテーブル構造が生成されます。
4. 最初のシナリオを確認します。その場合は、最初にTable per hierarchy structureまたはTable per Type structureを使用して修正する必要があります。おそらく、(私があなたの質問をよく理解していれば) 運用環境が既に存在するため、 階層構造ごとにテーブルを使用したいと思うでしょう。

于 2012-05-11T10:08:11.253 に答える
2

しばらく前に、コードでこれと非常によく似たエラーが発生しました。レッスンクラス内にキャンセルリストを入れてみてください。それが私の問題を解決したものです。

于 2012-05-09T19:15:28.600 に答える
1

私のプロジェクトがEF 6.0.2からEF 6.1.1に更新されたとき、私はそのような問題を抱えていました.6.0.2に戻って、古いバージョンが戻った後、エラーは消えました

于 2014-08-05T05:34:01.213 に答える