实体框架-插入具有多对多映射的模型

时间:2018-12-30 07:47:04

标签: entity-framework

当我这样设置模型时,如何插入属于模型Tag的模型Post

发布

public class Post
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
    public Post()
    {
       Tags = new List<Tag>();
    }
}

标记

public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }
}

此问题建议创建一个Post对象,然后将Tags添加到Tags集合中,但我无法正常工作: Insert/Update Many to Many Entity Framework . How do I do it?

我想在数据库中已经将Tag添加到Post,我该如何使用EF。我是EF的新手。

这是我尝试过的方法,如果我将其发送到API,它不会插入任何记录,并且我可以看到数据库中不存在新的tag Id = 0,但是我会认为这会导致外键约束错误,不确定是否需要为标签自动生成ID:

{
    Name: "test"
}

API

[ResponseType(typeof(Tag))]
public IHttpActionResult PostTag(Tag tag)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var post = new Post();
    var tags = new List<Tag>();
    tags.Add(tag);

    post.Tags.Add(tag);
    post.Id = 10;
    db.Entry(post).State = EntityState.Modified;
    db.SaveChanges();

    return CreatedAtRoute("DefaultApi", new { id = tag.Id }, tag);
}

1 个答案:

答案 0 :(得分:1)

如果您说存在Many-To-ManyPostTagTag之间的连接表的Post关系,那么您的模型不会显示任何many-to-many关系,所以从我所看到的 由于您的模型定义,one-to-manyPostTag之间。

如果要在它们之间建立many-to-many关系,则必须遵循以下条件:

public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Post> Posts { get; set; }
    public Tag()
    {
        Posts = new HashSet<Post>();
    }
} 
public class Post
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public virtual ICollection<Tag> Tags { get; set; } 
    public Post()
    {
        Tags = new HashSet<Tag>();
    }
}

,并在OnModelCreating中通过流利的api建立联系,如下所示:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{ 
    modelBuilder.Entity<Tag>()
        .HasMany(s => s.Posts)
        .WithMany(c => c.Tags)
        .Map(cs =>
        {
            cs.MapLeftKey("TagId");//TagId
            cs.MapRightKey("PostId");//PostId
            cs.ToTable("PostTag");
        });
}

反之亦然

modelBuilder.Entity<Post>()
    .HasMany(s => s.Tags)
    .WithMany(c => c.Posts)
    .Map(cs =>
        {
            cs.MapLeftKey("PostId");//PostId
            cs.MapRightKey("TagId");//TagId
            cs.ToTable("PostTag");
        });

您可以看到并知道数据库中应该有一个名为PostTag的表,该表具有两列作为键,并具有如下脚本:

CREATE TABLE [dbo].[PostTag](
    [TagId] [int] NOT NULL,
    [PostId] [int] NOT NULL,
 CONSTRAINT [PK_PostTag] PRIMARY KEY CLUSTERED 
(
    [TagId] ASC,
    [PostId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] 

ALTER TABLE [dbo].[PostTag]  WITH CHECK ADD  CONSTRAINT [FK_PostTag_Post] FOREIGN KEY([PostId])
REFERENCES [dbo].[Post] ([Id])
GO 
ALTER TABLE [dbo].[PostTag] CHECK CONSTRAINT [FK_PostTag_Post]
GO 
ALTER TABLE [dbo].[PostTag]  WITH CHECK ADD  CONSTRAINT [FK_PostTag_Tag] FOREIGN KEY([TagId])
REFERENCES [dbo].[Tag] ([TagId])
GO 
ALTER TABLE [dbo].[PostTag] CHECK CONSTRAINT [FK_PostTag_Tag]
GO

查看here以获得更多信息。

更新:

如果要在zero-to-manyPost之间建立Tag关系,则模型应如下所示:

public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? PostId { get; set; }
}
public class Post
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
    public Post()
    {
        Tags = new HashSet<Tag>();
    }
}

和流利的api一对多关系:

modelBuilder.Entity<Post>()
   .HasMany(o1 => o1.Tags);

作为注释,您不希望Tag具有导航属性,因此应在Nullable中将其定义为Tag作为伪键的属性,如果它们之间存在关系应该至少通过Navigation属性或Nullable属性建立关系。

正确答案来自here(没有变化): 您想要分配一个标签以存在帖子,您应该首先找到帖子,然后向其中添加一个标签,如果该标签确实存在于数据库中,则会在标签和找到的帖子之间建立关系,如果该标签不存在,则将插入标签到数据库,

看看这个:

var post = context.Posts.SingleOrDefault(x => x.Id == 4);//That Id would be you specific Post Id
var existTag = context.Tags.SingleOrDefault(x => x.Id == 1); //Exist Tag in DB
post.Tags.Add(existTag);
context.SaveChanges();
//Inserting new tag to DB and assign it to Post also
Tag newTag = new Tag // Does not exist in DataBase
{
    Name = "tag2"
};
post.Tags.Add(newTag);// By this tag2 will be insert into Tag table first and then added to post (insert new record to PostTag)
context.SaveChanges();