EF 4.1, наследование и связь с общим первичным ключом => ResultType указанного выражения несовместим - PullRequest
5 голосов
/ 11 июля 2011

Резюме

У меня есть три класса:

  • Account
  • SpecialAccount (наследуется от Account)
  • Profile (0..1 отношение к SpecialAccount)

Другими словами, SpecialAccount может иметь 0 или 1 Profiles. A Profile должен иметь SpecialAccount.

В EF это может быть установлено только как отношение общего первичного ключа.

При запросе profile и запросе материала из SpecialAccount (например, «найти профили, где profile.SpecialAccount.Name == "blah") я получаю эту ошибку:

{"ResultType указанного выражения несовместим с требуемым типом.
Выражение ResultType имеет вид «Transient.reference [EFInheritanceTest.Account]», но
Обязательный тип: «Transient.reference [EFInheritanceTest.SpecialAccount]».
\ r \ nИмя параметра: аргументы 1"}

Детали

Этот код иллюстрирует проблему:

namespace EFInheritanceTest
{
  class Program
  {
      static void Main(string[] args)
      {
         using (var context = new MyContext())
         {
            var t = context.Profiles.Where(p => p.SpecialAccount.Name == "Fred");
            Console.WriteLine(t.Count());

            Console.ReadKey();
         }
      }
  }

  public class MyContext : DbContext
  {
     public DbSet<Account> Accounts { get; set; }
     public DbSet<SpecialAccount> SpecialAccounts { get; set; }
     public DbSet<Profile> Profiles { get; set; }

     protected override void OnModelCreating(DbModelBuilder modelBuilder)
     {
         base.OnModelCreating(modelBuilder);

         modelBuilder.Entity<SpecialAccount>().HasOptional(a => a.Profile);
         modelBuilder.Entity<Profile>().HasRequired(p => p.SpecialAccount);
     }
  }

 public class Account
 {
     public int ID { get; set; }
     public string Name { get; set; }
 }

 public class SpecialAccount : Account
 {
      public virtual Profile Profile { get; set; }
 }

 public class Profile
 {
     public int ID { get; set; }
     public string Summary { get; set; }
     public virtual SpecialAccount SpecialAccount { get; set; }
 }
}

Расследования на данный момент

По сути, виновником является связь общего первичного ключа; Когда Profile ищет его SpecialAccount, он получает родительский объект Account.

Единственное решение, которое я вижу, это изменить его так;

public class SpecialAccount : Account
{
    public virtual ICollection<Profile> Profiles { get; set; }
}

и поддерживать правила в коде, а не использовать базу данных. Но это просто безобразно.

Я нашел этот связанный вопрос и эту ошибку в Connect - но она была помечена как решенная!?

Я подозреваю, что это ошибка в EF4.1, но если кто-то знает что-нибудь лучше или как обойти это, я был бы очень признателен за любые идеи.

1 Ответ

4 голосов
/ 11 июля 2011

В качестве обходного пути, который, кажется, работает без изменения определения модели, вы можете использовать соединение:

var t = from p in context.Profiles
        join s in context.SpecialAccounts
          on p.ID equals s.ID
        where s.Name == "Fred"
        select p;
var count = t.Count();

Или с методами расширения:

var t = context.Profiles
               .Join(context.SpecialAccounts,
                     p => p.ID,
                     s => s.ID,
                     (p, s) => new { s, p })
               .Where(r => r.s.Name == "Fred");
var count = t.Count();

Это не очень хорошо, ноТот факт, что ваш оригинальный запрос не работает, выглядит для меня как ошибка.(Я тестировал с EF 4.1)

...