1

データベースの行を削除し、同じ ID で再度挿入したいのですが、ばかげているように聞こえますが、シナリオは次のとおりです。

ドメイン クラスは次のとおりです。

public class SomeClass
{
    public int SomeClassId { get; set; }
    public string Name { get; set; }
    public virtual Behavior Behavior { get; set; }
}

public abstract class Behavior
{
    public int BehaviorId { get; set; }
}

public class BehaviorA : Behavior
{
    public string BehaviorASpecific { get; set; }
}

public class BehaviorB : Behavior
{
    public string BehaviorBSpecific { get; set; }
}

エンティティコンテキストは

public class TestContext : DbContext
{
    public DbSet<SomeClass> SomeClasses { get; set; }
    public DbSet<Behavior> Behaviors { get; set; }

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

        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

        modelBuilder.Entity<SomeClass>()
            .HasOptional(s => s.Behavior)
            .WithRequired()
            .WillCascadeOnDelete(true);

    }
}

これで、このコードを実行して要点を示すことができます (以下のコードにコメントで説明されています)。

    using(TestContext db = new TestContext())
    {
        var someClass = new SomeClass() { Name = "A" };
        someClass.Behavior = new BehaviorA() { BehaviorASpecific = "Behavior A" };
        db.SomeClasses.Add(someClass);

        // Here I have two classes with the state of added which make sense
        var modifiedEntities = db.ChangeTracker.Entries()
                                 .Where(entity => entity.State != System.Data.Entity.EntityState.Unchanged).ToList();
        // They save with no problem
        db.SaveChanges();

        // Now I want to change the behavior and it causes entity to try to remove the behavior and add it again
        someClass.Behavior = new BehaviorB() { BehaviorBSpecific = "Behavior B" };

        // Here it can be seen that we have a behavior A with the state of deleted and 
        // behavior B with the state of added
        modifiedEntities = db.ChangeTracker.Entries()
                 .Where(entity => entity.State != System.Data.Entity.EntityState.Unchanged).ToList();

        // But in reality when entity sends the query to the database it replaces the 
        // remove and insert with an update query (this can be seen in the SQL Profiler) 
        // which causes the discrimenator to remain the same where it should change.
        db.SaveChanges();
    } 

更新の代わりに削除と挿入が行われるように、このエンティティの動作を変更する方法は?

4

1 に答える 1

0

考えられる解決策は、2 つの異なる手順で変更を行うことです:someClass.Behavior = new BehaviorB() { BehaviorBSpecific = "Behavior B" };挿入前

someClass.Behaviour = null;
db.SaveChanges();

この動作は、データベース モデルに関連しています。EF の BehaviourA と B は、同じ EntityRecordInfo に関連付けられており、同じ EntitySet (Behaviors) を持ちます。DB モデルは同じままであるため、コンテキストで 2 つの異なる DbSet を作成した場合も同じ動作になります。

編集
1 対 1 の関係の同様の結果を達成する別の方法は、ComplexType を使用することです。それらは継承でも機能します。ここに例があります

public class TestContext : DbContext
{
    public TestContext(DbConnection connection) : base(connection, true) { }

    public DbSet<Friend> Friends { get; set; }
    public DbSet<LessThanFriend> LessThanFriends { get; set; }
}

public class Friend
{
    public Friend()
    {Address = new FullAddress();}

    public int Id { get; set; }
    public string Name { get; set; }

    public FullAddress Address { get; set; }
}

public class LessThanFriend
{
    public LessThanFriend()
    {Address = new CityAddress();}

    public int Id { get; set; }
    public string Name { get; set; }

    public CityAddress Address { get; set; }
}


[ComplexType]
public class CityAddress
{
    public string Cap { get; set; }
    public string City { get; set; }
}

[ComplexType]
public class FullAddress : CityAddress
{
    public string Street { get; set; }
}
于 2015-08-13T08:29:34.227 に答える