我正在学习EF Core。说我与一个联结表有很多对很多的关系:
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public int TagId { get; set; }
public Tag Tag { get; set; }
}
说我想执行数据库插入。
var post = new Post { Id=Guid.NewGuid(), Description="Test Post" };
var tag = new Tag { Id=Guid.NewGuid(), Description="Test Text" };
var PostTag = new PostTag { Post=post; Tag=tag; PostId=Post.Id, TagId=Tag.Id};
context.Add(PostTag);
此插入似乎出现:
1) Insert a post.
2) Insert a Tag
3) Insert a PostTag
Q1)为什么PostTag包含PostId和TagId?此信息包含在Post和Tag中(也是PostTag中的两个字段)。看来这些字段是重复的。
Q2)添加PostTag还会添加Post和Tag吗?
答案 0 :(得分:0)
为什么PostTag包含PostId和TagId?此信息包含在Post和Tag中(也是PostTag中的两个字段)。看来这些字段是重复的。
如您所知,PostTag.PostId
是引用Post.Id
的外键,而PostTag.TagId
是引用Tag.Id
的外键。分别称为PostTag.PostId
和Foreign Key Property
的{{1}}是PostTag.Post
。
实际上,如果您没有用于导航属性的外键属性,则Navigation Property
也会按预期工作。在这种情况下,将自动为您引入EF Core
和PostId
的两个影子外键属性。它称为Shadow Properties
。
可以通过约定在发现关系但在从属实体类中找不到外键属性的情况下创建阴影属性。在这种情况下,将引入影子外键属性。影子外键属性将被命名为
TagId
(命名实体使用指向主实体的依赖实体上的导航)。如果主键属性名称包含导航属性的名称,则名称将仅为<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
建议在相关实体类中为导航属性定义外键属性
添加PostTag还会添加Post和Tag吗?
您的代码会自动为您插入一个帖子和标签,因为它知道您需要创建一个全新的帖子和一个全新的标签。但这并不总是这样。它取决于跟踪状态和实体本身。
如果执行以下代码:
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; }
}
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
同样,它将在数据库中插入一个新的标记记录。有关更多信息,请参见docs here