英文:
Why does my optional one-to-one relationship with Entity Framework Core not work?
问题
以下是翻译好的代码部分:
// Principal(父表)
public class Person
{
[Key]
public int Id { get; set; }
public string LastName { get; set; }
public virtual Address Address { get; set; }
}
// Dependent(子表)
public class Address
{
public int? AddressRef { get; set; }
public string Street { get; set; }
public virtual Person Person { get; set; }
}
modelBuilder.Entity<Person>(entity =>
{
entity.ToTable("Person");
entity.HasKey(k => new { k.Id });
entity.Property(p => p.Id)
.HasColumnName("PersonRef");
});
modelBuilder.Entity<Address>(entity =>
{
entity.ToTable("Address");
entity.HasKey(x => x.AddressRef);
entity.Property(e => e.AddressRef).ValueGeneratedNever();
entity.HasOne(a => a.Person)
.WithOne(b => b.Address)
.HasForeignKey<Address>(c => c.AddressRef)
.IsRequired(false)
.OnDelete(DeleteBehavior.ClientSetNull).HasConstraintName("FK_dbo.Address_dbo.Person_AddressRef");
})
如果您需要进一步的帮助,请告诉我。
英文:
I have an existing sql database with 2 tables that have an optional one-to-one relationship with proper records.
I configured the given relationship with Entity Framework Core for my asp.net core web application as given below:
// Principal (parent)
public class Person
{
[Key]
public int Id { get; set; }
public string LastName { get; set; }
public virtual Address Address { get; set; }
}
// Dependent (child)
public class Address
{
public int? AddressRef { get; set; }
public string Street { get; set; }
public virtual Person Person { get; set; }
}
modelBuilder.Entity<Person>(entity =>
{
entity.ToTable("Person");
entity.HasKey(k => new { k.Id });
entity.Property(p => p.Id)
.HasColumnName("PersonRef");
});
modelBuilder.Entity<Address>(entity =>
{
entity.ToTable("Address");
entity.HasKey(x => x.AddressRef);
entity.Property(e => e.AddressRef).ValueGeneratedNever();
entity.HasOne(a => a.Person)
.WithOne(b => b.Address)
.HasForeignKey<Address>(c => c.AddressRef)
.IsRequired(false)
.OnDelete(DeleteBehavior.ClientSetNull).HasConstraintName("FK_dbo.Address_dbo.Person_AddressRef");
})
When I try to add a new Person via DbContext
var newPerson = new Person()
{
LastName = model.LastName,
// ...
};
DbContext.Add(newPerson);
DbContext.SaveChanges() // Error is thrown
I get the ErrorMessage:
> The value of 'Person.Id' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known.'
I have tried several variations for configuring the one-to-one relationship but all give the same error.
Any help would gratefully be appreciated.
答案1
得分: 1
以下是翻译的代码部分:
"Your principal entity's Primary Key should be annotated as AutoGeneratedValue.
modelBuilder.Entity<Person>(entity =>
{
entity.ToTable("Person");
entity.HasKey(k => k.Id); // .ValueGeneratedOnAdd(); problem was here
entity.Property(k => k.Id).ValueGeneratedOnAdd(); // <-- Here is the change
entity.Property(k => k.Id)
.HasColumnName("PersonRef");
});
Note: 主键
应该在 主实体
中被注释为 AutoGeneratedValue
,因为它将被用作 从属实体
中的主键。
并且,正如 @FFad3 所尝试告诉的,在您的情况下,Address
是可选的,而不是如我上面提到的 Person
。Address 的主键应该从 Person
表中的现有记录映射而来。您不能有一个 Address
记录而没有对应的人。
您可以将其更改为一对多的关系,以使这成为可能。这样,在 Person
表中,您将有一个与相关 Address
的 外键
(可空外键),以及 Address
实体上的单独的 主键
。
如果您问我,我会解释给您如何做到这一点。"
英文:
Your principal entity's Primary Key should be a annotated as AutoGeneratedValue.
modelBuilder.Entity<Person>(entity =>
{
entity.ToTable("Person");
entity.HasKey(k => k.Id); // .ValueGeneratedOnAdd(); problem was here
entity.Property(k => k.Id).ValueGeneratedOnAdd(); // <-- Here is the change
entity.Property(k => k.Id)
.HasColumnName("PersonRef");
});
Note: Primiary key
should have a value for Primary Key
in Principal Entity
because it will be used as primary key in the Dependent Entity
And as @FFad3 tried to tell, in your scenario Address
is Optional not Person
as I mentioned above the primary key of the Address should be Mapped from an existing record on Person
table. You can't have a record of Address
without having a corresponding person.
You may change it to one-to-many relation to make it possible. in this way in Person
table you will have a Foreign Key
for related Address
(nullable foreign key) and separated Primary key
on Address
entity.
If you ask me I will explain you how to do this.
答案2
得分: 0
我认为你应该更改
public virtual Address Address { get; set; }
为
public virtual Address? Address { get; set; }
同时检查迁移脚本,确保Person.Id已设置为SqlServer:Identity:
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1")
英文:
I think that you should change
public virtual Address Address { get; set; } => public virtual Address? Address { get; set; }
also check migration script if Person.Id is set to SqlServer:Identity
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1")
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论