I have two models that have a bi-directional 0-to-one relationship.
A, B. A may have a B. B may have an A.
Currently these are set up with navigational properties within each class, WITHOUT foreign key properties (set using fluent syntax)
public class A{
[key]
public int Id {get;set;}
public B B {get;set;}}
public class B{
[key]
public int Id {get;set;}
A A {get;set;}
}
modelBuilder.Entity()
.HasOptional(b => b.A)
.WithOptionalPrincipal()
.Map(b => b.MapKey("AId"));
modelBuilder.Entity()
.HasOptional(p => p.B)
.WithOptionalPrincipal()
.Map(p => p.MapKey("BId"));
So far things are working fine, as expected.
I would now like to expose these ID properties in my entities, so that to aid in updating disconnected entity relationships.
If I remove the maps, and then try to use the keys, it appears to work, but the migration decides to drop the FK columns, and then re-add them with a different name. This will break all my existing data.
I tried to rewrite the fluent mapping to use HasMany().HasForeignKey(), but that didn't work either. (Even though its not really many, that seems to be required to get the HasForeignKey method?)
What is the right way to upgrade this relationship while keeping the schema the same to preserve existing data in the database?
Solutions1
You current mapping generates the following migration:
CreateTable(
"dbo.B",
c => new
{
Id = c.Int(nullable: false, identity: true),
BId = c.Int(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.A", t => t.BId)
.Index(t => t.BId);
CreateTable(
"dbo.A",
c => new
{
Id = c.Int(nullable: false, identity: true),
AId = c.Int(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.B", t => t.AId)
.Index(t => t.AId);
As you can see, it is a 1-n relationship, not 1-0.1. The relationship "A may have a B; B may have an A" is not possible.
A may have B, but only one B, so B's primary key should also be A's foreign key.
That's ok. That's how a 1-0.1 relationship works. But on the other side, you want to do same.
B may have an A, but only one A, so A's primary key should also be B's foreign key.
That's not ok, you are trying to make a "real 1-1 relationship", which is not possible because you can't insert 2 rows at the same time.
What you want is a 1-n relationship. So, modify your classes as follow:
public class A
{
[Key]
public int Id { get; set; }
public int? BId { get; set; }
public B B { get; set; }
}
public class B
{
[Key]
public int Id { get; set; }
public int? AId { get; set; }
public A A { get; set; }
}
Mapping:
modelBuilder.Entity()
.HasOptional(i => i.B)
.WithMany()
.HasForeignKey(i => i.BId);
modelBuilder.Entity()
.HasOptional(i => i.A)
.WithMany()
.HasForeignKey(i => i.AId);
It generates the following migration (the properties' names might be inverted. In that case, just change BId to AId and AId to BId):
CreateTable(
"dbo.B",
c => new
{
Id = c.Int(nullable: false, identity: true),
AId = c.Int(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.A", t => t.AId)
.Index(t => t.AId);
CreateTable(
"dbo.A",
c => new
{
Id = c.Int(nullable: false, identity: true),
BId = c.Int(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.B", t => t.BId)
.Index(t => t.BId);
Hope it helps!