1

CodeFirst で POCO の子オブジェクトを更新する際に問題があります。私のPOCOは次のとおりです

public class Place
{
    public int ID { get; set; 
    public string Name { get; set; }

    public virtual Address Address { get; set; }
}

public class Address
{
    public int ID { get; set; 
    public string AddressLine { get; set; }
    public string City { get; set; }

    public virtual State State { get; set; }
}

public class State
{
    public int ID { get; set; 
    public string Name { get; set; }
}

場所とその子のすべてのフィールドを編集するビューがあります。DropDownList である State を除いて、すべてのプロパティはテキスト ボックスです。

ユーザーが保存ボタンをクリックすると、値が DropDownList から取得され、Name が空であるため、ID のみが入力されている State を除いて、ビューはすべての Place プロパティを返します。

Edit Post Method には、次のコードがあります。

if (ModelState.IsValid)
{
    bool isNewPlace = place.ID == -1;
    //Hack, State name is empty from View, we reload
    place.Address.State = new StateBLL().GetByID(place.Address.State.ID);
    new PlaceBLL().Update(place);

    return RedirectToAction("Index");
}

PlaceBLL クラスからの更新コードは次のとおりです。

protected override void Update(Place place)
{
    MyDbContext.Instance().Set<Address>().Attach(place.Address);
    MyDbContext.Instance().Entry(place.Address).State = System.Data.EntityState.Modified;
    MyDbContext.Instance().Set<State>().Attach(place.Address.State);
    MyDbContext.Instance().Entry(place.Address.State) = System.Data.EntityState.Modified;
    MyDbContext.Instance().SaveChanges();
    }

ユーザーが場所オブジェクトを編集すると、状態を除くすべてのフィールドが正しく更新されます。ユーザーがある場所の状態を変更すると、コードが最初にユーザーからの状態変更を検出しないように思われる場合、この変更はデータベースに保持されません。

コードが最初に Place から State 変更値を検出しない理由を知っていますか?

ありがとう。

4

2 に答える 2

1

Updateメソッドは (のスカラー プロパティ)Addressを更新し、 (のスカラー プロパティ) を更新しますが、との間の関係Stateを更新しません(別のエンティティを に割り当てずにビューのプロパティのみを編集しているように見えるため、これは問題ではありません) ととの間の関係は更新されません。しかし、これはあなたが実際にあなたの見方を変えたものです。placeAddressAddressAddressplaceplace.Addressplace.Address.State

と の関係を更新するには、次の 2 つのオプションがplace.Addressありplace.Address.Stateます。

  • Address状態への FK を表す外部キー プロパティをクラスに導入します(このタイプの関連付けは外部キー アソシエーションと呼ばれます)。

    public class Address
    {
        public int ID { get; set; 
        public string AddressLine { get; set; }
        public string City { get; set; }
    
        public int StateID { get; set; }
        public virtual State State { get; set; }
    }
    

    次に、ドロップダウン リストをplace.Address.StateID(ではなくplace.Address.State.ID) にバインドしていることを確認します。StateIDビューをサーバーにポストすると、ドロップダウン リストから選択した新しい ID がFK プロパティに取り込まれます。あなたのUpdate方法では、3行目と4行目を削除できます。単独で更新すると、外部キーAddressも更新されます。Edit Post アクションでStateIDロードするコードを削除することもできます。State

  • 現在の独立した関連付け (= モデル クラスで外部キー プロパティを公開しない関連付け)を維持したい場合は、データベースから元の状態を読み込み、新しい状態で更新する必要があります。

    protected override void Update(Place place)
    {
        var dbPlace = MyDbContext.Instance().Places.Include(p => p.Address.State)
            .Single(p => p.ID == place.ID);
    
        // Update scalar properties of place
        MyDbContext.Instance().Entry(dbPlace)
            .CurrentValues.SetValues(place);
    
        // Update scalar properties of Address
        MyDbContext.Instance().Entry(dbPlace.Address)
            .CurrentValues.SetValues(place.Address);
    
        // Change relationship between Adress and State
        if (dbPlace.Address.State.ID != place.Address.State.ID)
        {
            MyDbContext.Instance().States.Attach(place.Address.State);
            dbPlace.Address.State = place.Address.State;
        }
    
        MyDbContext.Instance().SaveChanges();
    }
    

    繰り返しますが、正しいキー プロパティ ( ) で関係を変更するのに十分なStateため、Edit Post アクションで をロードするコードを削除できます。State.ID

于 2012-12-29T16:04:07.267 に答える
0

また、エンティティをアタッチする必要があります。以下は、あなたがする必要があることの単純化したバージョンです。

var updated = _dbSet.Attach(item);
_dataContext.Entry(item).State = EntityState.Modified;
return updated;
于 2012-12-27T20:54:27.863 に答える