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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With