EF: 1:1 relationship independent association - entity-framework

I'm trying to create a simple 1:1 relationship with EF code first.
Example: A person always owns a single car and the car always belongs to a single person.
Person:
public class Person
{
public Guid Id { get; set; }
public string Name { get; set; }
public Car Car { get; set; }
}
// PersonEntityTypeConfiguration
HasKey(k => k.Id);
Property(p => p.Name).IsOptional();
HasRequired(n => n.Car).WithRequiredPrincipal().WillCascadeOnDelete(true);
Car:
public class Car
{
public Guid Id { get; set; }
public string SerialNumber { get; set; }
}
// CarEntityTypeConfiguration
HasKey(k => k.Id);
Property(p => p.SerialNumber).IsOptional();
This created the following migration script:
// Up
CreateTable(
"dbo.People",
c => new
{
Id = c.Guid(nullable: false),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.Cars",
c => new
{
Id = c.Guid(nullable: false),
SerialNumber = c.String(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.People", t => t.Id, cascadeDelete: true)
.Index(t => t.Id);
I expected EF to generate a foreign key like:
CreateTable(
"dbo.Cars",
c => new
{
Id = c.Guid(nullable: false),
SerialNumber = c.String(),
Person_Id = c.Guid()
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.People", t => t.Person_Id, cascadeDelete: true)
.Index(t => t.Id);
Why EF didn't create a foreign key like that?
How do I tell EF to generate the script that I expect?

If you want Car to have a foreign key to Person this is not a 1:1 association but 1:n (because n cars can refer to the same person).
What you see here is EF's way to enforce a 1:1 association: the primary key of the principal entity (Person) is copied to the primary key of the dependent entity (Car). The latter is also a foreign key to the principal.

Related

EF self referencing entity

Why is this EF 6 code generating an unexpected Code First Migration result?
I would expect this code to generate only one ParentId that is a self referencing FK.
This is based on the article attached at the end which was based on EF 4.1. Did anything change in EF 6 that could affect the behaviour in this case?
Entity:
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
public virtual Category Parent { get; set; }
public virtual ICollection<Category> Children { get; set; }
}
public class CategoryMap : EntityTypeConfiguration<Category> {
public CategoryMap() {
HasKey(x => x.CategoryId);
Property(x => x.CategoryId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(x => x.Name)
.IsRequired()
.HasMaxLength(255);
HasOptional(x => x.Parent)
.WithMany(x => x.Children)
.HasForeignKey(x => x.ParentId)
.WillCascadeOnDelete(false);
}
}
Code First Migration Result:
CreateTable(
"dbo.Categories",
c => new
{
CategoryId = c.Int(nullable: false, identity: true),
Name = c.String(),
ParentId = c.Int(),
Parent_CategoryId = c.Int(),
})
.PrimaryKey(t => t.CategoryId)
.ForeignKey("dbo.Categories", t => t.Parent_CategoryId)
.Index(t => t.Parent_CategoryId);
Code First Migration Expectation:
CreateTable(
"dbo.Categories",
c => new
{
CategoryId = c.Int(nullable: false, identity: true),
Name = c.String(),
ParentId = c.Int()
})
.PrimaryKey(t => t.CategoryId)
.ForeignKey("dbo.Categories", t => t.ParentId )
.Index(t => t.ParentId );
You can use this as a reference for further details: http://dotnet.dzone.com/news/using-self-referencing-tables

Why a new migration on making a property virtual?

I had entities such as this:
public class Foo
{
public int Id { get; set; }
public Bar Bar { get; set; }
public Bar2 Bar2 { get; set; }
}
public class Bar
{
public int Id { get; set; }
public string Description { get; set; }
}
public class Bar2
{
public int Id { get; set; }
public string Description { get; set; }
}
which migrations are:
CreateTable(
"dbo.Bar",
c => new
{
Id = c.Int(nullable: false, identity: true),
Description = c.String(),
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.Bar2",
c => new
{
Id = c.Int(nullable: false, identity: true),
Description = c.String(),
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.Foo",
c => new
{
Id = c.Int(nullable: false, identity: true),
Bar_Id = c.Int(),
Bar2_Id = c.Int(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Bar", t => t.Bar_Id)
.ForeignKey("dbo.Bar2", t => t.Bar_Id)
.Index(t => t.AlertCause_Id)
then I set a Bar property at Foo as virtual and it breaks with "AutomaticMigrationsDisabledException: Unable to update database to match the current model because there are pending changes and automatic migration is disabled." And after the migration re-scaffolding the code changes only in that Bar_Id becomes BarId but for Bar2 it remains Bar2_Id. So I wonder why it gets me the migration re-scaffolded if it seems it does not change anything? Yes it needs the proxy classes and lazy load, etc. but why a new migration? Thanks!
UPDATE
I've missed that the migration was actually triggered by the adding of a foreign key property, BarId. So my mistake here.
Found the reason. This is an incorrect question as the migration was triggered because of the adding a reference property (BarID). My mistake. So closing it.

Name of Foreign Key EF6

My entity has a List<SecondEntityDTO>. When EF generates the table, in the table SecondEntities there's a column name FirstEntityDTO_id. I would like this column to be named "ParentEntity_id". How can I do that?
I tried annotating the List of SecondEntityDTO and a bunch of other things...
Edit1: I belive you guys missunderstood.
This is my MainEntity:
[Table("MainEntities")]
public class MainEntityDTO
{
public string Title { get; set; }
[Key]
public int id { get; set; }
public List<SubEntityDTO> SubEntities { get; set; }
}
This is SubEntityDTO:
[Table("SubEntities")]
public class SubEntityDTO
{
[Key]
public int id { get; set; }
public string Title { get; set; }
}
And this is the Migration:
public override void Up()
{
CreateTable(
"dbo.MainEntities",
c => new
{
id = c.Int(nullable: false, identity: true),
Title = c.String(),
Discriminator = c.String(nullable: false, maxLength: 128),
})
.PrimaryKey(t => t.id);
CreateTable(
"dbo.SubEntities",
c => new
{
id = c.Int(nullable: false, identity: true),
Title = c.String(),
MainEntityDTO_id = c.Int(),
})
.PrimaryKey(t => t.id)
.ForeignKey("dbo.MainEntities", t => t.MainEntityDTO_id)
.Index(t => t.MainEntityDTO_id);
}
Note the name of the third column on the SubEntities table!
Also, you can do the same using Fluent Api, for example, overwritting the OnModelCreating method of your Context and doing this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<SecondEntity>().Property(s => s.FirstEntityDTO_id).HasColumnName("ParentEntity_id");
}
Update
Why you don't edit Func<> that specifies the columns of that table. As you can see you are creating an anonymous type, so you can change the name of the column there, eg:
CreateTable(
"dbo.SubEntities",
c => new
{
id = c.Int(nullable: false, identity: true),
Title = c.String(),
ParentEntity_id = c.Int(),
})
.PrimaryKey(t => t.id)
.ForeignKey("dbo.MainEntities", t => t.ParentEntity_id)
.Index(t => t.ParentEntity_id);
If you do this, remember change the name of that property in the Down method, but if you already executed that script, don't change the FK name yet in the Down method. Execute again the Update Database command specifying the name of that script. That will drop those tables and they will be created once again using the Up method, but now with the FK name that you want it.In that moment is when you can change the FK name in the Down method:
public override void Down()
{
DropForeignKey("dbo.SubEntities", "ParentEntity_id", "dbo.MainEntities");
DropIndex("dbo.SubEntities", new[] { "ParentEntity_id" });
DropTable("dbo.SubEntities");
DropTable("dbo.MainEntities");
}
Put the following code in your SubEntity class:
[ForeignKey("ParentEntity")]
public int ParentEntity_id { get; set; }
public virtual MainEntity ParentEntity { get; set; }

entity framework one to one with foreign key

It seems that Entity Framework have some conventions to deal with one to one relationship.
I'm using Fluent API and I need my child entity to have PK and Also FK.
Is it possible without using the [ForeignKey] attribute?
Consider the following example:
public class Principal
{
public int Id { get; set; }
public Dependent Dependent { get; set; }
}
public class Dependent
{
public int Id { get; set; }
public Principal Principal { get; set; }
}
To configure Dependent's Id property to be a foreign key to Principal's Id property with Fluent API you may choose one of the following options:
1) Starting with Entity<Dependent>:
public class AppDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Dependent>().HasRequired(d => d.Principal).WithOptional(p => p.Dependent);
}
}
2) Starting with Entity<Principal>
public class AppDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Principal>().HasOptional(p => p.Dependent).WithRequired(d => d.Principal);
}
}
They both will result in the following code first migration:
CreateTable(
"dbo.Principals",
c => new
{
Id = c.Int(nullable: false, identity: true),
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.Dependents",
c => new
{
Id = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Principals", t => t.Id)
.Index(t => t.Id);
where Dependent's Id property is configured to be as a PK and a FK to Principal's Id property.

WillCascadeOnDelete doesn't establish cascade delete on database

I don't know if I'm missing something obvious. We're using Entity Framework 6.0.0-rc1 in a project where the model is set up with the fluent API. Configuration of one of our entities could be:
HasMany(t => t.Entity)
.WithRequired(tc => tc.ParentEntity)
.HasForeignKey(tc => new {tc.Key1, tc.Key2})
.WillCascadeOnDelete(true);
When running this configuration, database gets created correctly, with all tables and fields. Even relationships are correctly established but not the delete cascade.
If I go to Management Studio and I inspect update/delete rules of the relationship, both are deactivated.
Thanks for your help.
With these classes:
public class Parent
{
public int ID { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child
{
public int ID { get; set; }
public int ParentID { get; set; }
public Parent Parent { get; set; }
}
Configured like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Parent>()
.HasMany(p => p.Children)
.WithRequired(c => c.Parent)
.HasForeignKey(c => c.ParentID)
.WillCascadeOnDelete(true);
}
Puts cascade delete on the foreign key:
public override void Up()
{
CreateTable(
"dbo.Children",
c => new
{
ID = c.Int(nullable: false, identity: true),
ParentID = c.Int(nullable: false),
})
.PrimaryKey(t => t.ID)
.ForeignKey("dbo.Parents", t => t.ParentID, cascadeDelete: true)
.Index(t => t.ParentID);
CreateTable(
"dbo.Parents",
c => new
{
ID = c.Int(nullable: false, identity: true),
})
.PrimaryKey(t => t.ID);
}