0

EFモデルで定義された単純な2オブジェクトの継承、Person<-Userがあります。

Personは基本エンティティ/クラスであり、抽象的ではなく、firstname、lastname、emailなどのフィールドが含まれています。

Userは派生エンティティ/クラスであり、username、lastlogin、islockedoutなどのフィールドが含まれています。

データベースはタイプごとのテーブルスキーマを使用するため、Person用に1つのテーブルがあり、User用に別のテーブルがあります。どちらも同じ主キーフィールドであるPersonIDを使用します。PersonIDはIDENTITY列ですが、EDMでは、PersonIDのStoreGeneratedPatternがNoneに設定されています。

これはタイプごとのテーブル継承スキーマであるため、対応するUser行/オブジェクトを持たないPerson行/オブジェクトが存在する可能性があります。これは、システムにユーザーではない人に関するデータを含めることができるようにするためです。しかし、人は最終的にユーザーになる可能性があり、これは私が問題を抱えているところです。

このシナリオのテストケースがあります。このシナリオでは、システムがユーザーになりたい人物を見つけます。新しいUserオブジェクトにPersonIDフィールドを設定し、それをObjectContextに追加して、変更を保存してみました。何が起こるかというと、データベースは、PersonIDに設定した値を無視して、新しいUser行とともに新しいPerson行を作成します。

どうすればこれを回避できますか?EDM Crud操作を処理するためにsprocを作成する必要がありますか?

4

2 に答える 2

2

ここにあなたの問題があります:

このシナリオのテストケースがあります。このシナリオでは、システムがユーザーになりたい人を見つけます。

オブジェクトは、C#または私が知っている他のクラスベースのOOPLではタイプを変更できません。EFはこれを変更しません。

デザインを変更する必要があります。OOではありません。私は昨年これについて書きました:

優れたオブジェクトリレーショナルマッピングを設計するときに克服しなければならない精神的な障壁の1つは、主にオブジェクト指向の用語またはリレーショナル用語のどちらか自分の性格に合ったもので考える傾向です。ただし、優れたオブジェクトリレーショナルマッピングには、優れたオブジェクトモデルと優れたリレーショナルモデルの両方が組み込まれています。たとえば、Peopleのテーブルと、EmployeesとCustomersの関連テーブルを含むデータベースがあるとします。1人の人が3つのテーブルすべてにレコードを持っている可能性があります。これで、厳密なリレーショナルの観点から、従業員用のデータベースVIEWと顧客用のデータベースVIEWを構築できます。どちらも、Peopleテーブルの情報を組み込んでいます。いずれかのビューを使用する場合、一時的に個人を「単なる」従業員または「単なる」顧客と考えることができます。あなたはそれらが両方であることを知っていても。したがって、この世界観から来た人は、従業員と顧客の両方が(直接の)PersonのサブクラスであるOOマッピングを実行したくなるかもしれません。しかし、これは私たちが持っているデータでは機能しません。1人の個人が従業員と顧客の両方のレコードを持っているため(そして、Personインスタンスが具体的なサブタイプの従業員と顧客を同時に持つことはできないため)、個人と従業員の間のOO関係は次のようになる必要があります。継承ではなく構成であり、個人と顧客についても同様です。

于 2010-09-24T16:40:38.513 に答える
0

私はこの問題を解決することができましたが、解決策に完全に満足しているわけではありません。結局、PersonとUserの両方の挿入、更新、および削除操作をマップするストアドプロシージャを作成しました(これらは同じエンティティセットにあるため、両方を3つのsprocすべてにマップする必要があります)。Userのinsertsprocは、PersonIDパラメーターを受け取り、それを使用して、新しいPerson行を作成するか、既存のPerson行にアタッチするかを決定します。

問題は、PersonIDをsproc入力パラメーターと結果列バインディングの両方としてマップする必要があることです。dbが新しいPersonIDを生成する必要がある場合、他のテーブルがPersonIDを参照する外部キー列の正しい値を取得するために、結果バインディングを使用してそれを元に戻す必要があります。ただし、User.PersonIDを入力パラメーターと結果列のバインドの両方として同時にマップすることはできません。これにより、実行時例外が発生します。「依存操作の有効な順序を判別できません。外部キーの制約、モデル要件、または生成された値の格納により、依存関係が存在する可能性があります。」

最終的に、null許容整数(BasePKと呼びます)である新しい列をUserテーブル(および対応する概念モデル)に追加しました。EDMでは、このプロパティのゲッターとセッターを保護して、パブリックインターフェイスから非表示にしました。次に、BasePKをsproc入力パラメーターとしてマップし、PersonIDを結果の列バインディングとしてマップして、ID値が生成された場合にそれを受け取ります。Userコンストラクターの1つのオーバーロードは、次のようになります。

public User(int personID):base(){this.BasePK = personID; }

したがって、既存のPersonをUserに変えたいときはいつでも、このオーバーロードを使用してユーザーを構築する必要があります。

int personID = [人を検索し、その人のPersonIDを返すための何らかのメソッド]; var User = new User(personID);

ObjectContextがエンティティを挿入するときに、BasePKプロパティを介してPersonIDをsprocに渡します。sprocが完了すると、PersonIDが実際の主キープロパティに返されます。

これを実現するために列とプロパティを追加する必要があるという考えは好きではありませんでしたが、Craigの答えに対する私のコメントと一致します:Personを変更/再構成することなく、新しい専門分野を持つPersonにプラグインできるようにしたい毎回エンティティ。このようにして、少なくとも、派生エンティティタイプのすべての変更を保持できます。これは、それらの変更に、物理ストアでは常にnullになる無意味な列の追加が含まれる場合でも同様です。

于 2010-09-25T14:40:18.350 に答える