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 。我该怎么做?
我想在数据库中添加标签到帖子,我怎么能用 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);
}
解决方案
如果您说存在Many-To-Many
关联PostTag
表之间的关系Tag
,Post
那么您的模型不会显示任何many-to-many
关系,那么从我所看到的情况来看
,由于您的模型定义,one-to-many
两者之间存在关联。Post
Tag
如果你想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
通过 fluent 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
看看这里了解更多信息。
更新:
如果你想建立zero-to-many
关系Post
,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>();
}
}
以及与 fluent api 的一对多关系:
modelBuilder.Entity<Post>()
.HasMany(o1 => o1.Tags);
作为您的评论,您不希望Tag
有导航属性,因此您应该定义一个属性Nullable
,Tag
其中是假键,如果它们之间存在关系,您应该至少通过导航属性或Nullable
属性建立关系。
正确答案来自这里(没有变化):您想为存在的帖子分配一个标签,您应该首先找到该帖子,然后为其添加一个标签,如果该标签确实存在于数据库中,则会在标签和找到之间建立关系发布如果该标签不存在,那么标签将被插入到数据库中,
看看这个 :
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();
推荐阅读
- javascript - 如何遍历 JSON 树
- c# - 排序列表并反转它们不起作用
- java - Android请求运行时权限不起作用
- xamarin - 从 HttpClient 响应 (POST) 中读取特定标头
- javascript - YouTube 自动播放解决方法?
- sqlite - 为什么我的 sqlalchemy/sqlite 更新这么慢?
- r - 将一行拆分为多行并出现变异错误
- php - Postman 的 GET 请求未显示 JSON 输出
- php - Symfony 3.4 - 刷新页面时会话丢失
- google-cloud-datastore - Firestore 更新的费用是否与写入费用相同?