追加された複数のエンティティが同じ主キーを持つ場合があります


81

これが、Route、Location、LocationInRouteの3つのエンティティのモデルです。
モデル

次のメソッドは失敗し、コミットすると例外が発生します。

 public static Route InsertRouteIfNotExists(Guid companyId, IListLocation> locations)
        {
            //Loop on locations and insert it without commit
            InsertLocations(companyId, routesOrLocations);

            RouteRepository routeRep = new RouteRepository();
            Route route = routeRep.FindRoute(companyId, locations);
            if (route == null)
            {
                route = new Route()
                {
                    CompanyId = companyId,
                    IsDeleted = false
                };
                routeRep.Insert(route);
                LocationInRouteRepository locInRouteRep = new LocationInRouteRepository();
                for (int i = 0; i < locations.Count; i++)
                {
                    locInRouteRep.Insert(new LocationInRoute()
                    {
                        //Id = i,
                        LocationId = locations[i].Id,
                        Order = i,
                        RouteId = route.Id
                    });
                }
            }
            return route;
        }

行うとき:

InsertRouteIfNotExists(companyId, locations);
UnitOfWork.Commit();

私が得た:

'SimTaskModel.FK_T_STF_SUB_LOCATION_IN_ROUTE_T_STF_LOCATION_location_id'関係のプリンシパルエンドを判別できません。追加された複数のエンティティが同じ主キーを持つ場合があります。

コミットを分割してメトスに挿入すると、次のように機能します。

  public static Route InsertRouteIfNotExists(Guid companyId, IListLocation> locations)
            {
                //Loop on locations and insert it without commit
                InsertLocations(companyId, routesOrLocations);
                UnitOfWork.Commit();

                RouteRepository routeRep = new RouteRepository();
                Route route = routeRep.FindRoute(companyId, locations);
                if (route == null)
                {
                    route = new Route()
                    {
                        CompanyId = companyId,
                        IsDeleted = false
                    };
                    routeRep.Insert(route);
                    LocationInRouteRepository locInRouteRep = new LocationInRouteRepository();
                    for (int i = 0; i < locations.Count; i++)
                    {
                        locInRouteRep.Insert(new LocationInRoute()
                        {
                            //Id = i,
                            LocationId = locations[i].Id,
                            Order = i,
                            RouteId = route.Id
                        });
                    }
                    UnitOfWork.Commit();
                }
                return route;
            }

メソッドの外で一度commitを呼び出したいと思います。最初の例で失敗する理由と、この例外の意味は何ですか?


9
@Ladislav Mrnka:私には上司がいません。これは私のプロジェクトです。私がすぐにSOに尋ねる印象をどこで得るのか本当にわかりません。一日中コンピュータを使用しているのはあなただけではありません。無料のコンサルティング?誰かが誰かに彼の答えを保証しますか?ここで質問できるフォーラムだと思います。これが私がやっていることです。多くの質問がありますが、このフォーラムとあなたのような人々のおかげで、私は長い距離を学ぶことができると信じています。参加は選択です。
Naor

1
@Ladislav:かなりよく聞かれる質問しか見られず、OPのプロファイルにも何も表示されていません。
ヘンクホルターマン

操作の範囲全体で同じObjectContextを使用していますか、それとも新しいリポジトリごとに独自のObjectContextがありますか?
Akash Kava

@Akash Kava:同じObjectContextを使用しています。
Naor

回答:


144

このエラーは、解決できない外部キーID(参照ではなく)が原因で発生します。あなたの場合、IDが0のロケーションを参照するLocationInRoleがあります。このIDを持つロケーションは複数あります。

ロケーションは、IDが生成された時点のデータベースにまだ保存されていないため、まだIDが割り当てられていません。2番目の例では、IDにアクセスする前に場所が保存されるため、これが機能します。

後でのみ変更を保存する場合は、ロケーションIDを使用して関係を定義することはできません。

次の行を入れ替えます...

LocationId = locations[i].Id

...このため...

Location = locations[i]

関係は、LocationIDに依存しないオブジェクト参照に基づいています。


あなたのどちらかが私の投稿を見て、それを修正する方法を教えてもらえますか、私は同じ問題を抱えています:stackoverflow.com/questions/26783934/…ありがとうございます!
duxfox-- 2014年

テスト環境にデプロイするとこのエラーが発生します... dev environemnetにアイデアはありませんか?
タラン2016

@Taranコードが同一で、同じプロセスを使用して両方の環境でテストしている場合(これらの点を確認します)、これは奇妙に思えます。たぶん、開発で1つの場所(ここの例に続く)だけを追加していますか?少なくとも2つ追加してみてください。
スコットマン

私の問題はこれのバリエーションかもしれません。子に親プロパティを明示的に設定せずに、子オブジェクトを親のコレクションに追加していました。EFがこれを解決することを期待していましたが、子に親プロパティを明示的に設定するまで、OPと同じエラーを受け取りました。これが誰かを助けることを願っています。
エリック

4

これが将来の読者に役立つ場合、私の場合、このエラーはデータベース(およびDBから生成されたモデル)で正しく構成されていない外部キーが原因でした。

私はテーブルを持っていました:

Parent (1-1) Child (1-many) Grandchild

そして、孫テーブルは、その親(子)とその祖父母(親)までの外部キーを誤って受け取っていました。newから複数のParentエンティティを保存すると、このエラーが発生しました。修正は外部キーを修正することでした。


私の場合は(愚かな)私の外部キー列と同じ私の外部キーベース表と私の主キー列と同じに私の主キーベーステーブルを設定していた恥に弓頭、これは誰かに役立ちます希望...
デイブ・

3

同じエラーが発生したので、実際の問題は場所の定義であると強く思います。簡単に言えば、EFコードファーストでは、次のようになっているに違いありません。

public class Location
{
    public int Id { get; set; }
    ...
    public Location ParentLocation { get; set; }
    [ForeignKey("ParentLocation")]
    public int ParentLocationId { get; set; }
}

つまり、質問では、ParentLocation / ParentLocationIdはこのテーブルへの再帰的な参照です。

ParentLocationIdはNullableではありません。つまり、0で挿入され、EFは移行時ではなく、挿入時に文句を言います。移行が実行されると、EFが挿入できないテーブルがあります。

同じテーブルへの再帰参照を機能させる唯一の方法は、再帰参照をnull許容にすることです。

public class Location
{
    public int Id { get; set; }
    ...
    public Location ParentLocation { get; set; }
    [ForeignKey("ParentLocation")]
    public int? ParentLocationId { get; set; }
}

?後に注意してくださいint


子の場所を作成する前に親の場所でSaveChangesを実行すると、古い(null許容ではない)バージョンは機能しませんか?
アンドレコップス2017年

1
上記を無視して、私はばかです。最初の場所を作成することはできません。
アンドレコップス2017年

カーディナリティが問題でした。正しい。
aclalex

0

この例外を探している人のために:
私の場合、必要なナビゲーションプロパティを設定できませんでした。

public class Question
{
    //...
    public int QuestionGridItemID { get; set; }
    public virtual QuestionGridItem GridItem { get; set; }
    //...
    public int? OtherQuestionID { get; set; }
    public Question OtherQuestion { get; set; }
}

//...

question.OtherQuestion = otherQuestion;
questionGridItem.Questions.Add(question);
dataContext.SaveChanges(); //fails because otherQuestion wasn't added to 
//any grid item's Question collection

0

私も同じ問題を抱えていました。以下のシナリオで解決しました。私はあなたが以下のようにあなたのコードを変更しなければならないと思います:

var insertedRoute =routeRep.Insert(route);
.....
insertedRoute.LocationInRoute = new List<LocationInRoute>();
for(....){
    var lInRoute = new LocationInRoute(){
    ....
    Route=insertedRoute;
}

insertedRoute.LocationInRoute.Add(lInRoute );
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.