I have a repro for what I think might be an EF bug. I would like to split one table across two entities. Each of those entites contains a reference to a third entity. The two references must be exposed with identical foreign key property names. Since they map to columns in the same table, configuration (or, in this example, an attribute) is used to make the column names unique.
When I try to load the model, I get the above exception from EF. If I modify the name of one of the FK properties then the error goes away.
Here is my model. The code as-is works. To reproduce the problem, rename Foo2.Foo3Id1
to Foo3Id
, which is the value that I need it to have.
Why Would You Want to Do That?
If you're wondering why I need the two properties to have the same name, here's the explanation.
I have a table that contains several addresses (e.g. a postal address and a billing address). This is an existing database, so I can't change the table structure. Each address is represented by a series of standard columns. The name of each column has a prefix identifying the kind of address and a suffix identifying the part of the address, e.g. BillingAddressLine1
, BillingAddressZipCode
and PostalAddressLine1
.
It would seem that using a complex type would handle this. However, there is an added complication: each address contains a CityId
that references a Cities
table. Complex types don't support relationships and navigation properties. So my intended solution is to use table splitting instead, and to split each set of address properties into its own entity. Each entity that represents an address either derives from a base type, say, Address
or implements an interface, IAddress
.
With table splitting I'm careful to observe the restriction that where several types are mapped to the same table, they must all have navigation properties to each other.
In the code below, Foo1
and Foo2
are both address types (and would implement some common interface). Foo3
is City
. This is the simplest repro of the problem that I could come up with.
Code Sample
class Program
{
static void Main(string[] args)
{
// Use NuGet to import EF 5 into the project.
// This code is just enough to cause the metadata to be loaded and therefore demo the error.
using (Context cx = new Context())
{
var qq = from f in cx.Foo3s
where f.Foo1s.Any()
select f;
}
}
}
[Table("Foo")]
public class Foo1
{
[Key]
public virtual int Id { get; set; }
[Required]
public virtual Foo2 Foo2 { get; set; }
[ForeignKey("Foo3")]
[Column("Foo1_Foo3Id")]
public virtual int? Foo3Id { get; set; }
public virtual Foo3 Foo3 { get; set; }
}
[Table("Foo")]
public class Foo2
{
[Key]
public virtual int Id { get; set; }
[Required]
public virtual Foo1 Foo1 { get; set; }
// Re-name the following property to Foo3Id (rather than Foo3Id1) and the model won't load.
// You get "InvalidOperationException: Sequence contains more than one matching element."
[ForeignKey("Foo3")]
[Column("Foo2_Foo3Id")]
public virtual int? Foo3Id1 { get; set; }
public virtual Foo3 Foo3 { get; set; }
}
[Table("Foo3")]
public class Foo3
{
[Key]
public virtual int Id { get; set; }
[InverseProperty("Foo3")]
public virtual ICollection<Foo1> Foo1s { get; set; }
[InverseProperty("Foo3")]
public virtual ICollection<Foo2> Foo2s { get; set; }
}
public class Context : DbContext
{
public DbSet<Foo3> Foo3s { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Don't think we can configure 1:1 relationship using just attributes.
var foo2 = modelBuilder.Entity<Foo2>();
foo2.HasRequired(q => q.Foo1)
.WithRequiredPrincipal(q => q.Foo2);
}
}
Is this a bug? Am I doing something wrong? Is it a known EF limitation?