It looks like you are trying to Extend EntityB
with an optional 1:1 reference to a Row n the new table EntityA
. You want both records to have the same value for Id.
This 1:1 link is sometimes referred to as Table Splitting.
Logically in your application the record from EntityB
and EntityA
represent the same business domain object.
If you were simply trying to create a regular 1 : many
relationship, then you should remove the HasOne().WithOne() as this creates a 1:1
, you would also not try to make the FK back to the Id property.
The following advice only applies to configure 1:1 relationship
you might use Table Splitting for performance reasons (usually middle tier performance) or security reasons. But it also comes up when we need to extend a legacy schema with new metadata and there is code that we cannot control that would have broken if we just added the extra fields to the existing table.
Your setup for this is mostly correct, except that EntityA.Id
cannot be nullable, as the primary key it must have a value.
public class EntityA
{
public int Id { get; set; }
public string Name { get; set; }
public EntityB { get; set; }
}
If you want records to exist in EntityA
that DO NOT have a corresponding record in EntityB
then you need to use another Id column as either the primary key for EntityA
or the foreign key to EntityB
You then need to close the gap with the EntityA.Id
field by disabling the auto generated behaviour so that it assumes the Id
value from EntityB
:
modelBuilder.Entity<EntityA>(e =>
{
e.HasKey(p => p.Id).ValueGeneratedNever();
e.HasOne(p => p.EntityB)
.WithOne()
.HasForeignKey<EntityB>(p => p.Id);
}
I would probably go one step further and add the Reciprocating or Inverse navigation property into EntityB
this would allow us to use more fluent style assignment, instead of using _dbContext.Add()
to add the record to the database:
public class EntityB
{
public int Id { get; set; }
public string Version { get; set; }
public virtual EntityA { get; set; }
}
With config:
modelBuilder.Entity<EntityA>(e =>
{
e.HasKey(p => p.Id).ValueGeneratedNever();
e.HasOne(p => p.EntityB)
.WithOne(p => p.EntityA)
.HasForeignKey<EntityB>(p => p.Id);
}
This allows you to add in a more fluent style:
var entityB = _dbContext.EntityB.FirstOrDefault(e => e.Id == 1);
entityB.EntityA = new EntityA { Name = "Test" };
_dbContext.SaveChanges();
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…