4

コードファーストアプローチと流暢な構成を使用して、EF4.3.1で単純な継承シナリオをセットアップしようとしています。

1対1のナビゲーションプロパティを持つ抽象基本タイプ「A」を作成しました。また、1対1のナビゲーションプロパティを持つ継承されたクラス「AA」は次のとおりです。

public abstract class A
{
    public Guid ID { get; set; }
    public B ChildB { get; set; }
}

public class AA : A
{
    public C ChildC { get; set; }
}

public class B
{
    public Guid ID { get; set; }
    public A Parent { get; set; }
}

public class C
{
    public Guid ID { get; set; }
    public AA Parent { get; set; }
}

public class AConfiguration : EntityTypeConfiguration<A>
{
    public AConfiguration()
    {
        this.HasRequired(o => o.ChildB)
            .WithRequiredPrincipal(o => o.Parent);

        this.Map(o =>
        {
            o.ToTable("A");
        });
    }
}

public class AAConfiguration : EntityTypeConfiguration<AA>
{
    public AAConfiguration()
    {
        this.HasRequired(o => o.ChildC)
            .WithRequiredPrincipal(o => o.Parent);

        this.Map(o =>
        {
            o.ToTable("AA");
        });
    }
}

public class BConfiguration : EntityTypeConfiguration<B>
{
    public BConfiguration()
    {
        this.HasRequired(o => o.Parent)
            .WithRequiredDependent(o => o.ChildB);

        this.Map(o =>
        {
            o.ToTable("B");
        });
    }
}

public class CConfiguration : EntityTypeConfiguration<C>
{
    public CConfiguration()
    {
        this.HasRequired(o => o.Parent)
            .WithRequiredDependent(o => o.ChildC);

        this.Map(o =>
        {
            o.ToTable("C");
        });
    }
}

public class DataContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add<A>(new AConfiguration());
        modelBuilder.Configurations.Add<AA>(new AAConfiguration());
        modelBuilder.Configurations.Add<B>(new BConfiguration());
        modelBuilder.Configurations.Add<C>(new CConfiguration());
    }

    public DbSet<AA> AASet { get; set; }
    public DbSet<B> BSet { get; set; }
    public DbSet<C> CSet { get; set; }
}

最初のレベルのナビゲーションプロパティを使用してデータを取り戻そうとすると、期待どおりに機能します。

... dataContext.AASet.Include("ChildB") ...

しかし、次のように継承されたタイプのナビゲーションプロパティを含めようとすると:

... dataContext.AASet.Include("ChildC") ...

実行時にEntityCommandCompilationExceptionが発生し、次の内部例外メッセージが表示されます。

指定された式のResultTypeは、必要なタイプと互換性がありません。式ResultTypeは'Transient.reference[... A]'ですが、必要なタイプは' Transient.reference[...AA]'です。パラメータ名:arguments [0]

誰かが同様の問題に遭遇しましたか?

おそらく何かが足りないのですが、このサンプルの何が問題なのかわかりません。

モデルを期待どおりに機能させるにはどうすればよいですか?

4

1 に答える 1

4

いいえ、何も見逃しません。実際、あなたは古いEntityFrameworkのバグに遭遇しました。2番目のクエリは次のように記述できます。

var result = dataContext.ASet.OfType<AA>().Include("ChildC").ToList();

(DbSetをに置き換える場合AASetASet

継承されたタイプでの1対1のマップされた子のこのタイプの積極的な読み込みには、この記事が適用されます:http ://weblogs.asp.net/johnkatsiotis/archive/2010/04/28/huge-ef4-inheritance-bug.aspx

バグはずっと前にここで報告されています:https ://connect.microsoft.com/VisualStudio/feedback/details/544639/ef4-inheritance-defined-using-queryview-doesnt-work-properly-with-association

バグはEF4.3.1にまだ存在します。しかし、Microsoftはこのスレッドで、バグが.NET 4.5(= EF 5.0)で修正されていることを発表しました。

関係が1対1ではなく1対多の場合、コードは機能します。レイジーロードまたは明示的なロードも同様に機能します(1対1の関係でも)、私は信じています:

var result = dataContext.ASet.OfType<AA>().ToList();
foreach (var item in result)
    dataContext.Entry(item).Reference(a => a.ChildC).Load();

ただし、これにより複数のクエリが生成されます。複数のクエリでパフォーマンスの問題が発生しない場合は、EF 5.0に移行できるようになるまで、最後の回避策をお勧めします。

于 2012-05-22T18:05:31.327 に答える