4

数時間の試行錯誤の後、同じ 2 つのタイプで一対多の関係と一対一の関係を確立する方法を説明するこのスレッドにたどり着きました。

ただし、カスケード削除でこれを機能させることはできません:

スローされる: 「依存操作の有効な順序を決定できません。外部キー制約、モデル要件、またはストアで生成された値が原因で、依存関係が存在する可能性があります。」(System.Data.UpdateException) Exception Message = "依存する操作の有効な順序を特定できません。依存関係は、外部キーの制約、モデルの要件、またはストアで生成された値が原因で存在する可能性があります。"、Exception Type = "System.Data.UpdateException "

これは、1:1 の関係 (以下のコードを参照) を設定解除していない場合にのみ発生します。無効な参照が作成されることを考えると、これは理にかなっていると思います。これを表現するためのより良い方法があるかどうか疑問に思っています。

サンプルコード:

class Program
{
    static void Main(string[] args)
    {
        Database.SetInitializer(new DropCreateDatabaseAlways<Context>());

        using (var ctx = new Context())
        {
            var user = new User();

            ctx.Users.Add(user);
            ctx.SaveChanges();

            var source = new PaymentSource();
            user.PaymentSources = new Collection<PaymentSource>();
            user.PaymentSources.Add(source);
            user.DefaultPaymentSource = source;
            ctx.SaveChanges();

            // if I don't do this, I get ordering exception
            user.DefaultPaymentSource = null;
            ctx.SaveChanges();

            ctx.Users.Remove(user);
            ctx.SaveChanges();

            Assert.Equal(0, ctx.Users.Count());
            Assert.Equal(0, ctx.PaymentSources.Count());
        }
    }
}

public class User
{
    public int Id { get; set; }

    public virtual ICollection<PaymentSource> PaymentSources { get; set; }
    public virtual PaymentSource DefaultPaymentSource { get; set; }
    public int? DefaultPaymentSourceId { get; set; }
}

public class PaymentSource
{
    public int Id { get; set; }
    public virtual User User { get; set; }
    public int UserId { get; set; }
}

public class Context : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<PaymentSource> PaymentSources { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<User>()
            .HasOptional(u => u.DefaultPaymentSource)
            .WithMany()
            .HasForeignKey(u => u.DefaultPaymentSourceId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<PaymentSource>()
            .HasRequired(p => p.User)
            .WithMany(p => p.PaymentSources)
            .HasForeignKey(p => p.UserId)
            .WillCascadeOnDelete();
    }
}
4

1 に答える 1

2

あなたの抽象化を説明する他のオプションをリストしました:

A.

そのような3つのテーブルを使用するのはどうですか:

user 1-* paymentSource
user 1-0..1 DefaultPaymentSource
DefaultPaymentSource 0..1-1 PaymentSource

またはこれ:

B.

user 1-* paymentSource
user 1-0..1 DefaultPaymentSource
DefaultPaymentSource --derive from--> PaymentSource

またはこれ:

C.

user 1-* paymentSource
PaymentSource has addtional boolean field for "IsDefault"

私は選択肢 B を最良の選択肢として投票します。

同じソース テーブルから同じ宛先テーブルへの 2 つのリレーションを持つことは、良い考えではないと確信しています。おそらく、データベースのベスト プラクティスに関する規則またはパターンに違反している可能性があります。

于 2012-05-14T16:11:25.937 に答える