2

次のEFコードの最初のコードがあります。次の例外が発生します。

「GiftCouponPayment」には ID 列が含まれていません。

データベースにテーブルが正常に作成されました。しかし、どうすればこの例外を取り除くことができますか? また、この例外の理由は何ですか?

注: ドメイン モデル (最初にコードを使用して記述) が保持されている (そしてデータをクエリできる) 限り、どのようなテーブル スキーマでもかまいません。

ここに画像の説明を入力

この例外を継続した後、次のような別の例外があります。

リレーションシップの外部キー プロパティを公開しないエンティティの保存中にエラーが発生しました。1 つのエンティティを例外のソースとして識別できないため、EntityEntries プロパティは null を返します。保存中の例外の処理は、エンティティ タイプで外部キー プロパティを公開することで簡単に行うことができます。詳細については、InnerException を参照してください。

{"PRIMARY KEY 制約 'PK_dbo.PaymentComponent' に違反しています。オブジェクト 'dbo.PaymentComponent' に重複するキーを挿入できません。\r\nステートメントは終了しました。"}

参考

  1. Entity Framework: テーブルを複数のテーブルに分割する

: 結果のデータベース スキーマは次のようになります。

ここに画像の説明を入力

コード:

public class MyInitializer : CreateDatabaseIfNotExists<NerdDinners>
{
    //Only one identity column can be created per table.
    protected override void Seed(NerdDinners context)
    {
        //context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX IX_Payment_PayedTime ON Payment (PayedTime)");
        context.Database.ExecuteSqlCommand("DBCC CHECKIDENT ('Payment', RESEED, 1)");
        context.Database.ExecuteSqlCommand("DBCC CHECKIDENT ('GiftCouponPayment', RESEED, 2)");
        context.Database.ExecuteSqlCommand("DBCC CHECKIDENT ('ClubCardPayment', RESEED, 3)");
    }
}

//System.Data.Entity.DbContext is from EntityFramework.dll
public class NerdDinners : System.Data.Entity.DbContext
{
    public NerdDinners(string connString): base(connString)
    { 
    }

    protected override void OnModelCreating(DbModelBuilder modelbuilder)
    {
        //Fluent API - Plural Removal
        modelbuilder.Conventions.Remove<PluralizingTableNameConvention>();

        //Fluent API - Table per Concrete Type (TPC)
        modelbuilder.Entity<GiftCouponPayment>()
            .Map(m =>
            {
                m.MapInheritedProperties();
                m.ToTable("GiftCouponPayment");
            });

        modelbuilder.Entity<ClubCardPayment>()
            .Map(m =>
            {
                m.MapInheritedProperties();
                m.ToTable("ClubCardPayment");
            });
    }

    public DbSet<GiftCouponPayment> GiftCouponPayments { get; set; }
    public DbSet<ClubCardPayment> ClubCardPayments { get; set; }
    public DbSet<Payment> Payments { get; set; }
}

public abstract class PaymentComponent
{
    public int PaymentComponentID { get; set; }
    public int MyValue { get; set; }
    public abstract int GetEffectiveValue();
}

public partial class GiftCouponPayment : PaymentComponent
{
    public override int GetEffectiveValue()
    {
        if (MyValue < 2000)
        {
            return 0;
        }
        return MyValue;
    }
}

public partial class ClubCardPayment : PaymentComponent
{
    public override int GetEffectiveValue()
    {
        return MyValue;
    }
}

public partial class Payment
{
    public int PaymentID { get; set; }
    public List<PaymentComponent> PaymentComponents { get; set; }
    public DateTime PayedTime { get; set; }
}

クライアント:

    static void Main(string[] args)
    {
        Database.SetInitializer<NerdDinners>(new MyInitializer());
        string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30";

        using (var db = new NerdDinners(connectionstring))
        {
            GiftCouponPayment giftCouponPayment = new GiftCouponPayment();
            giftCouponPayment.MyValue=250;
            
            ClubCardPayment clubCardPayment = new ClubCardPayment();
            clubCardPayment.MyValue = 5000;
                    
            List<PaymentComponent> comps = new List<PaymentComponent>();
            comps.Add(giftCouponPayment);
            comps.Add(clubCardPayment);

            var payment = new Payment { PaymentComponents = comps, PayedTime=DateTime.Now };
            db.Payments.Add(payment);

            int recordsAffected = db.SaveChanges();
        }
    }
4

3 に答える 3

3

TPC / TPT マッピングの ID フィールドを指定していません。継承があっても、TPH マッピングを実行していないときはこれを行う必要があります。(注意してください、私もMapInheritedProperties()電話で確信が持てません...これは一般的にTPHに使用されます... TPTではありません)

 //Fluent API - Table per Concrete Type (TPC)
 modelbuilder.Entity<GiftCouponPayment>()
      .HasKey(x => x.PaymentComponentID)
      .Map(m =>
      {
          m.MapInheritedProperties();
          m.ToTable("GiftCouponPayment");
      })
      .Property(x => x.PaymentComponentID)
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

これは、具象型からのすべてのクラス マッピングで行う必要があります。私だったら、GiftCoupon の TPH マッピングと他の継承マッピングを使用するので、ディスクリミネーター列を使用してオブジェクトのツリー全体を表す 1 つのテーブルができあがります。

とにかく...基本クラスに欠けている他のものは次のとおりです。

public byte[] Version { get; set; }

および関連するマッピング:

Property(x => x.Version).IsConcurrencyToken()

これにより、楽観的な同時実行が可能になります。

これが少し役立つことを願っています。さらに支援や説明が必要な場合はお知らせください。

于 2012-07-30T12:09:41.987 に答える
2

基本クラスでもFKを使用しているため、TPCに関する最初のアドバイスが正しくなかったようですPaymentComponent。表が表示されていますか?TPC継承の場合は存在しないはずです。TPT継承を使用してみてください(MapInheritedPropertiesマッピングから削除してください)。これは、同じ正しいデータベースで終了します。再シードは使用しないでください。Idは、テーブルのID列だけで制御されPaymentComponentます(現時点では)。

于 2012-07-24T14:34:58.323 に答える
2

PaymentComponent クラスで、ID を KeyAttribute で装飾します。

[Key]
public int PaymentComponentID { get; set; }
于 2012-07-24T15:13:18.663 に答える