为什么 PostTag 包含 PostId 和 TagId?此信息包含在 Post 和 Tag(也是 PostTag 中的两个字段)中。看来这些字段是重复的。
如您所知,PostTag.PostId 是引用 Post.Id 的外键,PostTag.TagId 是引用 Tag.Id 的外键。 PostTag.PostId 称为 Foreign Key Property 和 PostTag.Post 是 Navigation Property。
实际上,如果您没有明确的导航属性的外键属性,EF Core 也将按预期工作。在这种情况下,将自动为您引入PostId 和TagId 两个影子外键属性。它被称为Shadow Properties。
当发现关系但在依赖实体类中找不到外键属性时,可以按约定创建阴影属性。在这种情况下,将引入影子外键属性。影子外键属性将被命名为<navigation property name><principal key property name>(依赖实体上的导航,指向主体实体,用于命名)。如果主键属性名称包含导航属性的名称,则名称将只是 <principal key property name>。如果依赖实体上没有导航属性,则使用主体类型名称代替它。
-
虽然这些外键可以分别由PostTag.Post.Id 和PostTag.Tag.Id 推断出来,但它们不是重复的。
假设我们有一个现有的数据库,其中外键命名为fk_post_id 和fk_tag_id,并且您想将外键属性PostId 重命名为MyPostId,我们不能省略PostId 和TagId 属性:
public class PostTag
{
[Column("fk_post_id")]
public Guid MyPostId { get; set; }
[ForeignKey("MyPostId")]
public Post Post { get; set; }
[Column("fk_tag_id")]
public Guid TagId { get; set; }
public Tag Tag { get; set; }
}
建议在导航属性的依赖实体类中定义外键属性
添加 PostTag 是否也会添加 Post 和 Tag?
您的代码会自动为您插入帖子和标签,因为它知道您需要创建一个全新的帖子和一个全新的标签。但情况并非总是如此。这取决于跟踪状态和实体本身。
如果执行以下代码:
var tagTracked = this._dbContext.Tag.FirstOrDefault();
var post = new Post { Id=Guid.NewGuid(), Description="Test Post3" };
var PostTag = new PostTag {
Post=post,
Tag=tagTracked,
MyPostId= post.Id,
TagId= tagTracked.Id,
};
this._dbContext.Add(PostTag);
this._dbContext.SaveChanges();
tagTracked 不会被插入。如果要插入新的标签记录,需要将tag设为untracked:
var tagTracked = this._dbContext.Tag.AsNoTracking().FirstOrDefault();
tagTracked.Id = Guid.NewGuid();
var post = new Post { Id=Guid.NewGuid(), Description="Test Post3" };
var PostTag = new PostTag {
Post=post,
Tag=tagTracked,
MyPostId= post.Id,
TagId= tagTracked.Id,
};
this._dbContext.Add(PostTag);
this._dbContext.SaveChanges();
再次,它将在数据库中插入一条新的标签记录。更多信息请参考docs here