Entity Framework 6における多対多リレーションシップ+ TPH継承に関する問題

c# entity-framework entity-framework-6 many-to-many table-per-hierarchy

質問

私は、このタイプのマッピングをサポートする以前のバージョンにも当てはまると確信していますが、EF6の問題に取り掛かりました。手元にある質問への答えを知っていることを恐れていますが、私が何か間違っていることを願ったり、私がここに提示したものよりも良い回避策があります。全てのクラスは分かりやすくするために掘り下げられています。

ので、私は持っています

public abstract class SoftwareFirmware
{
    public long Id { get; private set; }
    public ICollection<DeviceType> DeviceTypes { get; private set; } 

    public SoftwareFirmware()
    {
        DeviceTypes=new HashSet<DeviceType>();
    }
}

そして

public class DeviceType
{
    public long Id { get; set; }
    public virtual ICollection<Firmware> AvailableFirmwareVerions { get; private set; }
    public virtual ICollection<Software> AvailableSoftwareVerions { get; private set; }

    public DeviceType()
    {
        AvailableFirmwareVerions = new HashSet<Firmware>();
        AvailableSoftwareVerions = new HashSet<Software>();
    }
}

あなたが見ることができるように、多対多の関係が定義されています。私はSoftwareFirmwareから派生した2つのクラスを定義しました。

public class Firmware : SoftwareFirmware {}

そして

public class Software : SoftwareFirmware {}

私は階層ごとの継承テーブルを使用しています。したがって、 SoftwareFirmwareFirmwareリミネータ列を使用して同じテーブルに格納されます。最後に、派生したDbContextOnModelCreatingメソッドの関係を

modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableFirmwareVerions).WithMany(firmware=>firmware.DeviceTypes);
modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableSoftwareVerions).WithMany(sofware=>sofware.DeviceTypes);

手元にある問題は、EFがデータベースを生成しようとしたときに次のように表示されるため、Entity Frameworkがこのマッピングで継承をサポートしていないように見えることです。

DeviceTypes:FromRole:NavigationProperty 'DeviceTypes'は無効です。 AssociationType 'DeviceType_AvailableSoftwareVerions'のFromRole 'DeviceType_AvailableSoftwareVerions_Target'の 'Software'タイプは、このNavigationPropertyが宣言されている 'SoftwareFirmware'タイプと完全に一致する必要があります。

これから、 SoftwareFirmwareを継承するタイプはNavigationPropertyには十分ではなく、 SoftwareFirmwareタイプでなければなりません。私がSoftwareFirmware基底クラスからDeviceTypeコレクションを引き裂き、それを派生クラスのそれぞれに複製すると、すべてのことがうまくいくが、それは確かに理想的ではない。

最後に、私の質問は、ベースクラスにナビゲーションプロパティを保持できるように、これを設定する別の方法がありますか?そうでない場合は、私が説明したものよりもきれいな回避策がありますか?


更新: WithManyのオーバーロードされたバージョンを使用せずに式を受け取り、ジャンクションテーブルを含まないデータベースを以前に図表化したので、SQL Server Management Studioが間違っていたようです。 SSMSは、データベースを削除して再作成した場合でも、新しいダイアグラムを追加するという点で、スキーマの変更がうまくいきません。再起動する必要があります。大きな痛みですが、私は逃げる...

最終回の努力として、マッピングのWithManyのパラメータのないバージョンにWithMany 、アプリケーションを再起動してデータベースを削除して再作成し、SSMSを再起動して、lo!ジャンクション・テーブルが作成されました。私がする必要があったのは、基本のSoftwareFirmwareクラスのDeviceTypesプロパティにIgnoreを追加するDeviceTypes 、すべてDeviceTypes生成されました。私のFluentAPIマッピングコードは次のようになります。

modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableFirmwareVerions).WithMany();
modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableSoftwareVerions).WithMany();
modelBuilder.Entity<SoftwareFirmware>().Ignore(s => s.DeviceTypes);

このスキーマを生成するものです。私が望むスキーマとほぼ同じです(追加のプロパティを無視してください)。

ここに画像の説明を入力

しかし、 WithManyへのパラメータなしの呼び出しでは、 WithManyのナビゲーションプロパティのみがフックアップされるため、 Software.DeviceTypesおよびFirmware.DeviceTypesへの更新はEFによって追跡されません。

受け入れられた回答

問題は、単一のSoftwareFirmware.DeviceTypesプロパティがあることですが、2つの別々の関係の一部としてそれを使用しようとしています。 SoftwareFirmware.DeviceTypesは、DeviceType.AvailableFirmwareVerionsとDeviceType.AvailableSoftwareVerionsの両方の逆数にすることはできません。

あなたがモデル化しようとしていることは、それらを別個の関係として扱うことのようなものだからです。ここには2つのオプションがあります...

オプション1:それは2つの別個の関係です

SoftwareFirmware.DeviceTypesを削除し、ファームウェアとソフトウェアにDeviceTypesプロパティを追加します。

これは、実際には、SoftwareFirmware.DeviceTypesプロパティにIgnoreを設定し、WithManyの空のオーバーロードを使用するときに行っていることです。あなたは2つの関係(1つのSoftware - > DeviceTypeともう1つのFirmware - > DeviceType)があり、逆の方法を指すナビゲーションプロパティがないことをEFに伝えています。あなたがSoftwareFirmware.DeviceTypesを無視したので、あなたのモデルの一部ではありません。

オプション2:それは1つの関係です

DeviceTypeの2つのナビゲーションプロパティを削除し、SoftwareFirmwareベースクラスへの単一のナビゲーションで置き換えます。内容をフィルタリングするfaçadeプロパティを、ソフトウェアとファームウェアに追加することができます(下記参照)

public class DeviceType
{
    public long Id { get; set; }

    public virtual ICollection<SoftwareFirmware> AvailableVerions { get; private set; }

    public virtual IEnumerable<Firmware> AvailableFirmwareVerions
    {
        get
        {
            return this.AvailableVerions.OfType<Firmware>();
        }
    }

    public virtual IEnumerable<Software> AvailableSoftwareVerions
    {
        get
        {
            return this.AvailableVerions.OfType<Software>();
        }
    }

    public DeviceType()
    {
        AvailableVerions = new HashSet<SoftwareFirmware>();
    }
}

人気のある回答

この問題はよく知られています。 (私の電子メールをチェックする...それは1年以上前でした!)私は誰かに流暢なAPIの関係が失敗していたサンプルを私に送ってきました。彼らにはたくさんの人がいませんでしたが、同じ問題だと思います。私はそれを見て長い時間を費やして、(チームの)Rowan Millerに尋ねました。彼は流暢なAPIが基底型から来る財産を理解できないと言いました。

つまり、Fluent APIはAvailableSoftwareVerionsやAvailableFirmwareVersionsを見ているときDEVICETYPEプロパティを見ることができません。 (私はあなたにこれが何であるかは言えませんが、それは反射を通して見つけることができると思うでしょうが、おそらくこのシナリオを念頭に置いて設計されていないかもしれません)。

これはまだ私には意味がありませんでしたので、彼はさらに説明しました(そして、私はあなたのタイプについて少し説明しましたが、少し相違しています。

概念的には、DeviceTypeは多くのソフトウェアやファームウェアを持つことができるので、クラスは本当に意味をなさないが、逆ナビゲーションプロパティはSoftwareFirmwareで定義されている。ファームウェアやソフトウェアにDeviceTypeがないものが発生した場合はどうなりますか?それは> DeviceType.AvailableSoftwareVersionsとして設定されていますが、それはうまく動作しません。画像からEFを取り除いても、それをモデル化する正しい方法は、ProjectプロパティをReportにすることです。

それはEF5でした。私の記憶が正しければ同じ問題ですが、それはEF6のために変更されていないかもしれません。おそらく、この問題を解決するためにそこに問題があるかどうかを調べる必要があります。しかし、彼のさらなる説明は、バグではなく保護であることを示唆しています。

(私は彼にpingして前の問題を正しく推測していることを確認します)。

このメールでは、回避策としてナビゲーションプロパティの代わりにゲッターロジックを使用することを提案しました。



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ