EF table splitting: InvalidOperationException - sequence contains more than one matching element - entity-framework

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?

This was indeed a bug, and it has now been fixed. See http://entityframework.codeplex.com/workitem/643.

The bug was still around in 6.0. Have a look here: https://entityframework.codeplex.com/workitem/546
+ another related bug: https://entityframework.codeplex.com/workitem/2116

Related

One-to-one mapping in multiple tables

I'm trying to solve one puzzle, but with no luck so far.
I have an article (or blog post) and comment entities, they both have content. In order to support lazy loading for content (there is no need to load the content when I need to display a list of articles or comments) I decided to move content to separate table and organize one-to-one mapping. Here is an example of what I think:
public class Content {
[Key]
public int ID { get; set; }
public string RawContent { get; set; }
// a bunch of scalar properties, like content type and so on
}
public class BlogArticle {
[Key]
public int ID { get; set; }
public int ContentID { get; set; }
[ForeignKey(nameof(ContentID)]
public virtual Content Text { get; set; }
// other properties related to BlogArticle
}
public class Comment {
[Key]
public int ID { get; set; }
public int ContentID { get; set; }
[ForeignKey(nameof(ContentID)]
public virtual Content Text { get; set; }
// other properties related to comment
}
<...>
From first look it seems ok: I can create blog articles, comments and attach content (at first I insert content, obviously). Update works as well. However, deletion doesn't work: when I delete blog article or comment, content is not deleted (but I want to delete it when blog article or comment are deleted, not opposite).
From what I understand my biggest issue because of relationship direction: in my case, Content entity is principal end and BlogArticle and Comment are dependent ends. In order to solve the puzzle, I need to change principal/dependent relationship. Again, from what I understand in order to change relationship direction I need to have a foreign key in Content entity and use fluent API to describe who is parent (principal) and who is child (dependent) in one-to-one relationship. Since many tables (there might be other entities with content property) are pointing to Content table, it doesn't seem very easy. Am I correct in my understanding?
One possible solution I could imagine is to create multiple foreign keys in Content table and point to each related table:
public class Content {
[Key]
public int ID { get; set; }
public string RawContent { get; set; }
// foreign keys
public int BlogArticleID { get; set; }
public int CommentID { get; set; }
public int WebWidgetID { get; set; }
// other foreign keys if necessary
}
probably, foreign keys must be nullable (because only single foreign key is used at once). Then use Entity Framework fluent API to describe relationship directions and organize cascade delete. For me it looks ugly, but I have no other ideas.
My question: is my proposed solution good/reliable? Are there other options I can look at?
Thanks in advance!
All your thoughts are correct. And your proposed solution is the only way with traditional relational design. The drawback of course is the need of multiple mutually exclusive nullable FKs.
The other options I see are as follows:
(1) Using EF inheritance for the entities holding Content. e.g.
public abstract class EntityWithContent
{
[Key]
public int ID { get; set; }
public virtual Content Text { get; set; }
}
public class BlogArticle : EntityWithContent
{
// other specific properties
}
public class Comment : EntityWithContent
{
// other specific properties
}
and configured one-to-one relationship between Content (dependent) and EntityWithContent (principal) using either shared PK association or FK association.
But since EF Core currently supports only TPH strategy (i.e. all the derived entities share one and the same table with union of all fields), I won't recommend it.
(2) Making Content owned type.
This is closer to the intent, but unfortunately EF Core currently always loads the owned entity data along with the owner data (even if they are configured to be provided by different database tables), which is against your original goal, so I won't suggest that either.
(3) Using table splitting feature.
If the main goal is simple to support controlled (lazy/eager/explicit) loading and the Content is always required, then this might be the best solution so far.
It would require a bit more configuration, but at the end it will give you the original table design (single table per entity) with the desired loading behavior:
Model:
public abstract class Content
{
[Key]
public int ID { get; set; }
public string RawContent { get; set; }
// a bunch of scalar properties, like content type and so on
}
public class BlogArticle
{
[Key]
public int ID { get; set; }
public virtual BlogArticleContent Text { get; set; }
// other properties related to BlogArticle
}
public class BlogArticleContent : Content
{
}
public class Comment
{
[Key]
public int ID { get; set; }
public virtual CommentContent Text { get; set; }
// other properties related to comment
}
public class CommentContent : Content
{
}
Note that here Content class is not part of EF inheritance hierarchy, but simple base class with the common properties (abstract modifier is not strongly necessary). The actual derived classes might or might not define their own properties.
Configuration:
modelBuilder.Entity<BlogArticle>().ToTable("BlogArticles");
modelBuilder.Entity<BlogArticle>()
.HasOne(e => e.Text)
.WithOne()
.HasForeignKey<BlogArticleContent>(e => e.ID);
modelBuilder.Entity<BlogArticleContent>().ToTable("BlogArticles");
modelBuilder.Entity<Comment>().ToTable("Comments");
modelBuilder.Entity<Comment>()
.HasOne(e => e.Text)
.WithOne()
.HasForeignKey<CommentContent>(e => e.ID);
modelBuilder.Entity<CommentContent>().ToTable("Comments");

EF7 Scaffolding not creating columns

I have a model that looks like this:
public class Order
{
// removed irrelevant other properties
public Guid Id { get; set; }
public Address BuyerAddress { get; set; }
public Address SellerAddress { get; set; }
}
public class Address
{
public Guid Id { get; set; }
public string Street { get; set; }
public Order Order { get; set; }
}
In the DbContext I hooked them up like this:
entityTypeBuilder.HasOne(x => x.BuyerAddress).WithOne(x => x.Order).IsRequired(false);
entityTypeBuilder.HasOne(x => x.SellerAddress).WithOne(x => x.Order).IsRequired(false);
When I run
dnx ef migrations add Foo
dnx ef database update
The table is being created with some of the properties, but other properties, like the SellerAddress are missing (the BuyerAddress is being created fine though).
The same problem for other entities, such as User <-> BankAccount which is a 1:1 relationship that is defined as entityTypeBuilder.HasOne(x => x.BankAccount).WithOne(x => x.User).IsRequired(false);
Does anyone know what's up? I'm using Entity Framework 7.0.0-rc1-final. The issue is driving me crazy.
I fixed the problem. First I had foreign key properties, so my models looked like this:
public Order Order {get;set;}
public Guid OrderId {get;set;}
I didn't like this, and it resulted in duplicate columns in the database, so I removed the [EntityName]Id properties from my model. But because of this, EF got all confused could not longer figure out what I was trying to do. So for all 1:1 relationships I simply removed the navigation property on one side of the equation (so now Order has a reference to an Address, but Address no longer has a navigation property back to Order). This solved the problem.
So in case of the sample code in my question, I removed the Order property from Address.

EF CF - How do I build optional:optional relationship?

I want Foo to have an optional Bar and Bar to have an optional Foo.
I seemed to manage to get it working but I had an extra column being created on only one of the tables, e.g. it made InvitationId and then also Invitation_Id in SQL on only one of the tables, even though both entities are setup the same way, but in reverse.
So I wanted to make a smaller repro so I could ask the question on SO, but in the process, and although I have just copied the original entities, removed some properties, I now have a different error, which is worryingly non-deterministic.
Ok, code.
[Table("Foo")]
public partial class Foo
{
[Key]
public Guid Id { get; set; }
[Required]
[StringLength(128)]
public string Name { get; set; }
// Referential
[ForeignKey("Bar")]
public Guid? BarId { get; set; }
public virtual Bar Bar { get; set; }
}
[Table("Bar")]
public partial class Bar
{
[Key]
public Guid Id { get; set; }
[Required]
[StringLength(128)]
public string Name { get; set; }
// Referential
[ForeignKey("Foo")]
public Guid? FooId { get; set; }
public virtual Foo Foo { get; set; }
}
And in OnModelCreating
modelBuilder.Entity<Foo>()
.HasOptional<Bar>(foo => foo.Bar)
.WithOptionalPrincipal(bar => bar.Foo);
The error is:
The navigation property 'Foo' declared on type 'Product.Data.Entities.Bar' has been configured with conflicting foreign keys.
The original entities still exist in the project and are setup in exactly the same way except they have more properties, but they get created without error, except one has the extraneous FK column.
So there's a number of issues:
Why did I get the extra Invitation_Id column when it already has InvitationId?
Why can I not reproduce it?
Why does the error now appear? And if I solve that, is it going to help me with my original entities if they don't have the same issue.
What's the proper way of achieving my objective in my opening sentence above?
Meanwhile, I'm going to begin building Foo and Bar back into Invitation and Expectation bit by bit until it goes funny.
Update
So I ended up with EXACT copies of the original entities in all but name. These copies caused the FK conflict error above, but the originals do not!!
I then removed the originals and renamed the copies to their original names, changing none of the properties or attributes, and the error went away and I was back to the original issue of the extraneous FK column!
Bonkers.
Luke
The first thing is in an one to one relationship one end must be the principal and the another one is the dependent, so you can't specify a FK property in both entities. The second thing is if you are going to use a FK property, EF requires the PK of the dependent entity should be FK too:
public class Principal
{
public int Id{get;set;}
public virtual Dependent Dependent{get;set;}
}
public class Dependent
{
[Key, ForeignKey("Principal")]
public int PrincipalId{get;set;}
public virtual Principal Principal{get;set;}
}
The third thing is EF lets you configure a one-to-one relationship with optional in both sides using Fluent API, but you can specify the FK, because as I said before, it should be configured as PK too, so EF will handle that FK for you in DB, that's way you have an extra Invitation_Id column.
To resolve your issue your model should be this way(remove the FK properties):
[Table("Foo")]
public partial class Foo
{
[Key]
public Guid Id { get; set; }
[Required]
[StringLength(128)]
public string Name { get; set; }
// Referential
public virtual Bar Bar { get; set; }
}
[Table("Bar")]
public partial class Bar
{
[Key]
public Guid Id { get; set; }
[Required]
[StringLength(128)]
public string Name { get; set; }
// Referential
public virtual Foo Foo { get; set; }
}
And use the same Fluent Api configuration:
modelBuilder.Entity<Foo>()
.HasOptional(foo => foo.Bar)
.WithOptionalPrincipal(bar => bar.Foo);
About why the exception is not happened in your real code, I think the same as #user2697817, you should be creating two different relationships, but I can fully ensure that because I'm not seeing your real model.
A second option could be the solution that is showed by #user2697817, but in that case you are going to have two different relationships.
As I mentioned in my comment, because there is two relationships and it's possible to have a navigation property for each side of the relationship I think EF is having trouble distinguishing which navigation prop is part of which relationship.
I would suggest defining both relationships explicitly in your OnModelCreating
modelBuilder.Entity<Foo>().HasOptional(f => f.Bar)
.WithMany()
.HasForeignKey(f => f.BarId);
modelBuilder.Entity<Bar>().HasOptional(b => b.Foo)
.WithMany()
.HasForeignKey(b => b.FooId);

Entity Framework with Proxy Creation and Lazy Loading disabled is still loading child objects

I'm having some issues with the Entity Framework using POCOs and I hope someone can tell me at a high level if the behaviour I'm seeing is expected or I need to dig deeper into why it's happening.
I have a class Customer and another CustomerType, so Customer has a property Type (of type CustomerType indicating the type) and CustomerType has property Customers which is a collection of Customers (All Customers that have that type) So these are basically the Navigation properties on both ends of an association, resulting in POCO code something like:
public partial class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int TypeId { get; set; }
public CustomerType Type { get; set; }
}
public partial class CustomerType
{
public CustomerType()
{
this.Customers = new HashSet<CustomerType>();
}
public int Id { get; set; }
public string TypeName { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
}
I have turned off Proxy creation and LazyLoading (i.e. both DbContext.Configuration.ProxyCreationEnabled=false and DbContext.Configuration.LazyLoadingEnabled=false) because they make Serialization a pain.
As expected when I get instances from the Customer set, the Type property on them is null by default.
But if I get instances from the Customer set with a .Include("Type") not only is it loading the Type properties, but it's also loading the children - i.e. the collection of Customers on each of these.
Is this expected?
It is semi expected. The Include extension affects the SQL that is run. Those CustomerTypes that ARE loaded (by virtue of being included in the Customer query) will be built into the object tree according to the CustomerType.ParentId column.
So if by some fluke both a parent and a child is loaded in the same query, the child will be stuffed into the parent.

Deletion of entire entity graph, including relationships, using EF Code First

I have classes that are structured like the following:
public class Forecast
{
[Key]
[ForeignKey("Stop")]
public string Abbreviation { get; set; }
public virtual Stop Stop { get; set; }
public virtual List<Direction> Directions { get; set; }
}
public class Direction
{
public int DirectionId { get; set;}
public string Abbreviation { get; set;}
public virtual Forecast Forecast { get; set;}
public virtual List<Transport> Transports { get; set;}
}
public class Transport
{
public int TransportId { get; set; }
public int DirectionId { get; set;}
public virtual Direction Direction { get; set;}
}
public partial class Stop
{
[Key]
public string Abbreviation { get; set; }
public virtual Forecast Forecast { get; set; }
}
I developed these classes and used EF Code First 4.1 to generate the database. CF does appear to properly create all of the primary and foreign key relationships between the classes within the database (MSSQL).
My problem is when I want to delete a Forecast. I thought I do could something like the following:
using (MyContext ctxt = new MyContext())
{
// get a forecast, somehow, not really important
// The one assumption is I'm absolutely sure it's
// Abbreviation key already exists in the database
// and the list of Forecasts.
Forecast f;
ctxt.Forecasts.Remove(f);
}
This deletes the top-level object from the database just fine. However, all of its child objects - all of the directions and transports - remain in the database and become orphaned (their key relationship column gets set to null. I expect that but I DON'T know why they're not just deleted). I have resorted to recursing down the object graph and calling Remove on every object from its appropriate DbSet in ctxt, but that seems like... the wrong way to do it.
What am I missing here?
Why can't I just say
ctxt.Forecasts.Remove(f);
and be done with it?
Edit:
#Ladislav gave me the right answer - I
needed to add [Required] to the
Abbreviation property on Direction.
However, I am still forced to actually
load the child entities for this to
work - doing something as simple as
Direction d = f.Directions[0];
will cause the delete to actually
delete the child entities. I'm well
aware that this is due to lazy
loading. I thought the point of the
FK relationship and ON CASCADE DELETE
was that you wouldn't have to actually
load the entities to delete them?
Again I seem to be missing something simple.
#Eranga is right that this is done by ON DELETE CASCADE setting on relation in the database BUT you are using code first approach and EF creates database for you so the problem here is that your model is not correctly defined because EF didn't create cascading rule for you.
Why? Because of this:
public class Direction
{
public int DirectionId { get; set; }
public string Abbreviation { get; set; }
public virtual Forecast Forecast { get; set; }
public virtual List<Transport> Transports { get; set; }
}
Abbreviation is FK property and it is nullable! So EF looks at your model and it sees that you defined Direction entity which can have Abbreviation set to null and because of that it can exists orphaned. Change it to:
public class Direction
{
public int DirectionId { get; set; }
[Required]
public string Abbreviation { get; set; }
public virtual Forecast Forecast { get; set; }
public virtual List<Transport> Transports { get; set; }
}
and removing Forecast will delete all related Direction instances and Transport instances. Stop is different story because it is parent entity to Forecast so it will never be removed with Forecast.
Edit:
One more point - you don't want to add ON DELETE CASCADE to your relations manually because EF have to know about enabled cascade deletes. EF use this information in case where you have related entities loaded.
If you place the rule manually into the database you must use fluent mapping and tell EF about this rule as well. Once you force cascade delete in fluent api you don't need to make it manually in the database - it will be created automatically during database recreation.
You can easily achieve this by setting ON DELETE CASCADE when you create foreign keys in the Database.