以多对多关系使用联结表

时间:2018-11-27 20:47:22

标签: asp.net-core entity-framework-core

我正在学习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吗?

1 个答案:

答案 0 :(得分:0)

  

为什么PostTag包含PostId和TagId?此信息包含在Post和Tag中(也是PostTag中的两个字段)。看来这些字段是重复的。

如您所知,PostTag.PostId是引用Post.Id的外键,而PostTag.TagId是引用Tag.Id的外键。分别称为PostTag.PostIdForeign Key Property的{​​{1}}是PostTag.Post

实际上,如果您没有用于导航属性的外键属性,则Navigation Property也会按预期工作。在这种情况下,将自动为您引入EF CorePostId的两个影子外键属性。它称为Shadow Properties

  

可以通过约定在发现关系但在从属实体类中找不到外键属性的情况下创建阴影属性。在这种情况下,将引入影子外键属性。影子外键属性将被命名为 TagId (命名实体使用指向主实体的依赖实体上的导航)。如果主键属性名称包含导航属性的名称,则名称将仅为 <navigation property name><principal key property name> 。如果从属实体上没有导航属性,那么将使用主体类型名称代替。

  1. 尽管这些外键可以分别由<principal key property name>PostTag.Post.Id进行推断,但它们不是重复的

    假设我们有一个现有数据库,其中外键分别命名为PostTag.Tag.Idfk_post_id,并且您想将外键属性fk_tag_id重命名为PostId,我们不能省略MyPostIdPostId属性:

    TagId
  2. 建议在相关实体类中为导航属性定义外键属性

  

添加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