5

子行の変更と追加を同時に行うと、いくつかの問題が発生します。私は答えのテクニックを使用しています:stackoverflow.com/questions/5557829 /...。

問題は次のコードにあります。

public void EditReport(tbl_inspection inspection)
{
    foreach (var roll in inspection.tbl_inspection_roll)
    {                    
        container.tbl_inspection_roll.Attach(roll);
        container.ObjectStateManager.ChangeObjectState(roll, (roll.id_inspection_roll == 0) ? EntityState.Added : EntityState.Modified);
    }

    container.SaveChanges();
}

更新する行は常に少なくとも 1 行あります。追加する行が1つある場合、問題なく動作します。問題は、同時に複数の行を追加しようとすると、よく知られているエラーが表示されることです:

同じキーを持つオブジェクトが ObjectStateManager に既に存在します。ObjectStateManager は、同じキーを持つ複数のオブジェクトを追跡できません。

ここで何かが欠けているように感じます...

4

3 に答える 3

1

ここでの問題は、2 つ以上の子スタブが同じキー 0 を持っているためです。最初のオブジェクトをアタッチしようとすると、エラーが発生します。

メソッドは、ある種の DTO を使用して再設計する必要があります (ViewModel オブジェクトをドメイン モデル レイヤーに渡すのは正しくないと思います。そのため、スタブを使用していました)。または、コントローラーから直接追加/変更する関数を呼び出します。

編集:

コードは次のとおりです。

public void EditReport(Inspection obj)
{
    var inspection = new tbl_inspection
    {
        id_inspection = obj.ID,
        code = obj.Code       
    };

    foreach (var roll in obj.Rolls)
    {                    
        var rollStub = new tbl_inspection_roll
        {
            id_inspection_roll = roll.ID,
            id_inspection = obj.ID,
            description = roll.Description
        };

        container.tbl_inspection_roll.Attach(roll);
        container.ObjectStateManager.ChangeObjectState(roll, (roll.id_inspection_roll == 0) ? EntityState.Added : EntityState.Modified);
    }

    container.tbl_inspection.Attach(inspection);
    container.ObjectStateManager.ChangeObjectState(inspection, EntityState.Modified);

    container.SaveChanges();
}

より良い解決策は歓迎されます...

于 2013-01-04T13:34:41.727 に答える
1

追加されたものから変更されたものを分離する必要があると思います。Ladislav にリンクした質問には、この例として次のコードがありました。

if (myEntity.Id != 0)
{
    context.MyEntities.Attach(myEntity);
    context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified);
}
else
{
    context.MyEntities.AddObject(myEntity);
}

context.SaveChanges();

AddObject を使用する代わりに、特に Attach を使用することがエラーの原因であると思います。

編集:代わりに、アタッチ部分に対して次のことを試してください:

var r = new tbl_inspection_roll { id_inspection_roll = roll.id_inspection_roll };
container.tbl_inspection_roll.Attach(r);
container.Entry(r).CurrentValues.SetValues(roll);
于 2013-01-03T15:23:10.563 に答える
0

私が問題を正しく理解している場合、ParentObject と関連する ChildObjects を含むオブジェクト グラフを保存しようとしており、Attach() がデータベース内の ChildObjects とアタッチされた ParentObjects の間の Id 衝突を調整できないため、例外が発生しています。

以下は、私が過去に使用した回避策です。それはきれいではありませんが、それは仕事を成し遂げます。

public ParentObject Upsert(ParentObject newParentObject)
{
    // Check for an existing ParentObject.
    ParentObject exisitingParentObject = container.ParentObjects.SingleOrDefault(o => o.Id == newParentObject.Id);

    // If not an existing ParentObject
    if (exisitingParentObject == null)
    {
        // Add a new ParentObject
        exisitingParentObject = container.ParentObjects.Add(container.ParentObjects.Create());
    }

    // Update the properties of the existing ParentObject with the values of the new ParentObject
    var parentEntry = container.Entry(exisitingParentObject);
    parentEntry.CurrentValues.SetValues(newParentObject);

    // Remove ChildObjects that are in the existing but not in the new.
    for (int i = exisitingParentObject.ChildObjects.Count() - 1; i >= 0; i--)
    {
        ChildObject exisitingChildObject = exisitingParentObject.ChildObjects[i];
        if (!newParentObject.ChildObjects.Any(o => o.Id == exisitingChildObject.Id))
        {
            container.ChildObjects.Remove(exisitingChildObject);
        }
    }

    // Upsert new ChildObjects
    foreach (ChildObject newChildObject in newParentObject.ChildObjects)
    {
        // Check for an existing ChildObject
        ChildObject exisitingChildObject = exisitingParentObject.SingleOrDefault(o => o.Id == newChildObject.Id);

        // If not an existing ChildObject
        if (exisitingChildObject == null)
        {
            // Add a new ChildObject
            exisitingChildObject = exisitingParentObject.ChildObjects.Add(container.ChildObject.Create());
        }

        var childEntry = container.Entry(exisitingChildObject);
        childEntry.CurrentValues.SetValues(newChildObject);
    }

    container.SaveChanges();

    return exisitingParentObject;
}
于 2013-01-03T20:21:27.293 に答える