39

ねえ、私はたくさんのinprocキャッシングとエンティティフレームワークを備えたアプリケーションを持っています。エンティティに更新を書き込みたい場合は、キャッシュされたコピーを再アタッチします。コンテキストのライフサイクルで添付したものをすべて追跡するので、それらを2回添付しようとはしません。

アタッチ時にエラーが発生します(ほとんどの場合、これは正常に機能し、非常に高速です)。これは次のようになります。

参照整合性制約違反が発生しました:参照制約を定義するプロパティ値が、関係のプリンシパルオブジェクトと依存オブジェクトの間で一貫していません。

私は、正常に見えるエンティティを非常に注意深く調べました。この問題は、修正が実行されたときの外部キーのアタッチ/デタッチが原因だと思います。

このエラーに関する詳細情報を取得するための良い方法はありますか、それともエンティティがEFが予期していなかった状態にあった以外の理由で発生する可能性がありますか?

編集:DBダイアグラム(コードファーストを使用していることに注意してください。EDMXツールを使用してダイアグラムを作成しました。また、簡単にするために、モデルから多数の通常のプロパティを切り取りました)

ここに画像の説明を入力してください

4

7 に答える 7

54

エラーは、多対多の関係に加えて、モデル内の1対多の関係で発生する可能性がPersonあります。Locationたとえば、次のコードは例外をスローします。

using (var context = new MyContext())
{
    var person = new Person
    {
        CurrentLocationId = 1,
        CurrentLocation = new Location { Id = 2 }
    };
    context.People.Attach(person); // Exception
}

「参照制約を定義するプロパティ値」は、外部キープロパティ値CurrentLocationIdと主キー値CurrentLocation.Idです。これらの値が異なる場合、例外がスローされます。(許可CurrentLocationされているかのように持ってnullいます。)

私の意見では、この例外は外部キーの関連付けに対してのみスローできます。これは、このタイプの関連付けに対してのみ、モデルに参照制約を定義するプロパティがあるためです。独立した協会のために投げることはできません。すべての多対多の関係は独立した関連付けであるため(モデルに外部キープロパティがない)、エラーは多対多の関係ではなく、1対多に関連していると思います。

于 2012-07-21T22:45:06.640 に答える
10

私は非常によく似た例外に遭遇しました:

"A referential integrity constraint violation occurred: 
The property value(s) of 'ObjectA.PropertyX' on one end of a relationship 
do not match the property value(s) of 'ObjectB.PropertyY' on the other end."

理由は次のとおりです。WebAPIのクライアント側は、ナビゲーションプロパティを含むオブジェクト全体を含むPUTリクエストを送信しました(この例では、ObjectA(より正確にはObjectB.ObjectA)はナビゲーションプロパティであり、クライアントによって完全に提供されました)。これは、クライアントがサーバーからオブジェクト全体を受け取り、小さな変更を加えてそのままサーバーにバウンスするために発生します。

一方、ObjectB.PropertyYは変更されたばかりです(これが、そもそもPUTリクエストの理由でした)。

ObjectB.PropertyYは同じオブジェクトObjectA(外部キー)への参照であったため、EFはこれを調整しようとしましたが、上記の例外で失敗しました。

解決策は簡単でした:

ObjectB.ObjectA = null;

SaveChanges()がこれを完全に解決する前に。

これが誰かに役立つことを願っています。

于 2018-01-30T08:08:56.923 に答える
2

私はちょうど同じ問題を経験していて、私の解決策は、関連付けにマッピングを追加してから、参照制約を設定することでした。

この問題を解決するには、関連付けのマッピングウィンドウを開く必要があり、マッピングを削除するためのリンクがありました。[マッピングの詳細]ウィンドウが完了すると、[マッピングは許可されません]と表示されます。参照制約を追加すると、マッピングがそのまま残るようです。

他の誰かが将来このエラーメッセージの解決策を探している場合に備えて、投稿する価値があるかもしれないと思いました。

于 2014-09-19T08:29:01.623 に答える
1

@LukeMcGregorこんにちは、

同じ問題を抱えている人とは違う視点を提供できると思います。

必要なチェックをすべて実行した後、このエラーが発生することを望んでいると言えます。

私のシナリオでは、不一致エラーの原因となったオブジェクトを含めたかったためです。これは、シナリオ内のロケーションオブジェクトです。IDを持つオブジェクトを追加すると、前のオブジェクト(更新されていないオブジェクト)のIDが更新されたIDと一致しないため、このエラーが発生します。

しかし、それは大きな問題ではありません。解決策として; それがまだUI側にある場合、オブジェクトがまだ存在していれば、オブジェクトが含まれている可能性があります。

ユーザーから更新要求を受け取ったときに、オブジェクトを空にします。(= Null)または、サービス側の更新(アタッチ、変更など)の前にユーザーが更新したIDでオブジェクトを更新し、この方法で更新します。

それでおしまい。データベースや図にそのまま残すことができます。

于 2017-08-28T08:49:45.083 に答える
1

@Slaumaの答えに追加するのは、コンテキストにオブジェクトを追加するときだけではありません。たとえば、PersonでCurrentLocationIdを編集する場合は、Personオブジェクトに埋め込まれているCurrentLocationオブジェクトも編集する必要があります。CurrentLocationIdはCurrentLocationのテーブルに外部キーを持っているため、EFはCurrentLocationオブジェクトに自動的にデータを入力します。CurrentLocationオブジェクトも更新せずにCurrentLocationIdを編集すると、それらは同期しなくなります。これが、この場合の例外の原因です。

したがって、PersonオブジェクトのCurrentLocationIdを更新する必要があるとしましょう。個人データと場所データをプリフェッチしたと仮定します。

public class DbData 
{
    List<Person> PersonList;
    List<Location> LocationList;
    public DbData()
    {
        using (var context = new MyContext())
        {
             PersonList = context.Persons.ToList();
             LocationList = context.Locations.ToList();
        }
    }

    public void UpdatePersonLocation(Person person, int newLocationId)
    {
        using (var context = new MyContext())
        {
            var location = LocationList.Where(l=>l.id==newLocationId).Single();
            //you need to update both the id and the location for this to not throw the exception
            person.CurrentLocationId == newLocationId;
            person.CurrentLocation == location;  
            context.Entry(person).State = System.Data.Entity.EntityState.Modified;
            context.SaveChanges();
        }
    }
    //or if you're giving it the location object...
    public void UpdatePersonLocation(Person person, Location location)
    {
        using (var context = new MyContext())
        {
            //you need to update both the id and the location for this to not throw the exception
            person.CurrentLocationId == location.id;
            person.CurrentLocation == location;  
            context.Entry(person).State = System.Data.Entity.EntityState.Modified;
            context.SaveChanges();
        }
    }
}
于 2018-11-07T18:02:10.757 に答える
0

私はちょうどこの問題を抱えていて、かなり迅速な解決策を思いついた。私の問題は、非常に多くのテーブルにありました。

Public class Pictures_Tag
{
    [Key]
    [Column(Order = 0)]
    [ForeignKey("Picture")]
    public Int16 Picture_ID { get; set; }
    [Key]
    [Column(Order = 1)]
    [ForeignKey("ImageTag")]
    public Int16 ImageTag_ID { get; set; }
    public virtual Picture Picture { get; set; }
    public virtual ImageTag ImageTag { get; set; }
}

割り当てた行を追加したところ、Picture = db.Pictures...正常に機能しました(理由は正確にはわかりません)

[HttpPost]
public ActionResult Edit2(WebSiteEF2017C.Models.Pictures_Tag p)
{     
    using (var db = new thisModel(Session["org"].ToString())
    {
         p.Picture = db.Pictures.Where(z => z.ID == p.Picture_ID).FirstOrDefault();
         db.Pictures_Tags.Attach(p);
         db.Entry(p).State = EntityState.Modified;
         db.SaveChanges();
         return View(db.Pictures_Tags.Include(x => x.Picture)
                    .Where(n => n.Picture_ID == p.Picture_ID & n.ImageTag_ID == p.ImageTag_ID).FirstOrDefault());
    }
}
于 2018-05-30T23:28:06.303 に答える
0

サブクラスオブジェクトをnullに設定してみてくださいMainObject.SubObject1=null; Person.Address = null; //IDではなくnullになるオブジェクトをアドレス指定します

于 2021-03-10T21:51:41.310 に答える