Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF 4.1, inheritance and shared primary key association => The ResultType of the specified expression is not compatible

Summary

I have three classes:

  • Account
  • SpecialAccount (inherits from Account)
  • Profile (0..1 relationship to SpecialAccount)

In other words, a SpecialAccount can have 0 or 1 Profiles. A Profile must have a SpecialAccount.

In EF, this can only be set up as a shared primary key relationship.

When querying the profile and asking about stuff from the SpecialAccount (for example, "find profiles where profile.SpecialAccount.Name == "blah") I get this error:

{"The ResultType of the specified expression is not compatible with the required type.
The expression ResultType is 'Transient.reference[EFInheritanceTest.Account]' but
the required type is 'Transient.reference[EFInheritanceTest.SpecialAccount]'.
\r\nParameter name: arguments1"}

Details

This code illustrates the problem:

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; }
 }
}

Investigations so far

Basically, the culprit seems to be the shared primary key association; When the Profile goes looking for its SpecialAccount, it instead gets the parent Account object.

The only solution I can see is to change it like so;

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

and maintain the rules in code rather than using the database. But it's just ugly.

I found this related question and this bug on Connect - but that has been marked as resolved !?

I suspect this is a bug in EF4.1 but if anyone know any better or of a way around it then I'd be most grateful for any insights.

like image 575
flytzen Avatar asked Oct 11 '22 13:10

flytzen


1 Answers

As a workaround which seems to work without changing your model definition you can use a join:

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();

Or with extension methods:

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();

That's not very nice but the fact that your original query doesn't work looks indeed like a bug to me. (I've tested with EF 4.1)

like image 59
Slauma Avatar answered Oct 30 '22 21:10

Slauma