EF7 Scaffolding not creating columns - entity-framework

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.

Related

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

EF Code First Table Splitting issue when used with many-to-many relationships

I am trying to use "Table Splitting" in EF Code First and it works fine when I use one of the entities relationships of type one-to-many, but as soon as I use it in a many-to-many relationship I start getting this error:
(27,6) : error 3018: Problem in mapping fragments starting at line
27:Foreign key constraint 'Itinerary_Addresses_Target' from table
ItineraryAddress (Address_Id) to table User (Id): The columns of table
ItineraryAddress are mapped to AssociationSet Itinerary_Addresses's
End Itinerary_Addresses_Target but the key columns of table User are
not mapped to the keys of the EntitySet Addresses corresponding to
this End.
Here is the code (https://github.com/jorgef/tablesplitting):
Table Splitting
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public User User { get; set; }
}
modelBuilder.Entity<User>().ToTable("Users");
modelBuilder.Entity<Address>().ToTable("Users");
modelBuilder.Entity<User>().HasRequired(u => u.Address).WithRequiredPrincipal(a => a.User);
One-To-Many Relationship
public class Itinerary
{
public int Id { get; set; }
public ICollection<Address> Addresses { get; set; }
}
With the previous code, everything works like a charm, the problem is when introducing a many-to-many relationship
Many-To-Many Relationship
public class Address
{
...
public ICollection<Itinerary> Itineraries { get; set; }
}
After adding that relationship, the app raises the mentioned exception on runtime. I managed to save to disk the generated edmx just in case that helps, here is the link: https://github.com/jorgef/tablesplitting/blob/master/TableSplitting/SavedModel.edmx
If somebody wants to play with the two versions of the app, the one working and the one not working, I have two different commits:
Table splitting working with one to many relationship
Table splitting not working with many to many relationship
Any ideas or thougths are appreciated.
Many thanks!
In case anyone else has encountered this issue:
This was a bug in Entity Framework. The bug has since been fixed, and upgrading to EF6 will resolve the issue. See the following discussion for details:
https://entityframework.codeplex.com/workitem/1385
A related bug with table splitting validation has also been discovered and fixed, planned to be released with EF6.1.0:
https://entityframework.codeplex.com/workitem/1611

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.

Why is my EF CodeFirst configuration not using the specified foreign key property?

I have the following model:
public class Hotfix
{
public int? released_version { get; set; }
public virtual ReleaseVersion ReleasedVersion { get; set; }
}
In my mapping class (which is correctly being looked at) I have:
this.Property(t => t.released_version).HasColumnName("released_version");
this.HasOptional(t => t.ReleasedVersion)
.WithMany(t => t.ReleaseVersionForHotfix)
.HasForeignKey(d => d.released_version);
However, when I perform a query such as _context.Hotfixes.ToList() I get the exception Invalid column name 'ReleaseVersion_id'..
Why is it looking for a ReleaseVersion_id column when it's being told the column should be mapped to released_version?
This is using CodeFirst on an existing database
Ok I finally figured this out, and apparently it was due to some code not shown. There seems to be a bug in EF's fluent mapping when extra properties exist that are not mapped. I should have shown the ReleaseVersion structure which looks like:
public class ReleaseVersion
{
public int id { get; set; }
public virtual ICollection<Hotfix> CurrentVersionForHotfix { get; set; }
public virtual ICollection<Hotfix> ReleaseVersionForHotfix { get; set; }
public virtual ICollection<Hotfix> hotfixes2 { get; set; }
}
What's significant is the extra hotfixes2 property. This property was created by the EF 4.1 CodeFirst power tools, but I didn't remove it because I wanted to get everything working first.
Anyways, the hotfixes2 property had no relationship mapping in the hotfix EF configuration mapping class but for some reason this one extra property was causing the whole hotfix configuration to be disgarded. Simply removing the hotfixes2 property from the ReleaseVersion POCO caused my application to correctly work without errors.

Exact purpose of Entity Framework navigation properties

please have a look at the following POCOs:
public class Country
{
[Key]
public Guid ID { get; set; }
[Required]
public virtual Currency Currency { get; set; }
}
public class Currency1
{
[Key]
public Guid ID { get; set; }
public virtual ICollection<Country> Countries { get; set; }
}
public class Currency2
{
[Key]
public Guid ID { get; set; }
}
I am not exactly sure what I need navigation properties like the ICollection in Currency1 for. If it comes to EF CodeFirst I see no difference in the database structure created. The tables of Currency1 and Currency2 look pretty much the same to me. So why or when does it make sense to add this extra property?
Of course, just thinking of the POCOs I understand that I can't access any countries from a Currency2 object. For example:
var a = currency1.Countries; // works fine
var b = currency2.Countries; // does not even compile
But is this the only difference? In other words: If I do not need to access countries from a Currency2 object, there is no need to add a corresponding navigation property in the Currency2 class for the purposes of EF? Kind of confused here...
Navigation properties are used either for direct access (as you described) or in linq-to-entities queries. If you don't plan to use it you can remove it from your model. Just be aware that you need a navigation property on at least one side to be able to model database realation using the code first approach.