Asp.net core 实体框架核心存储来自多个数据源的多对多关系
如何正确实现实体框架核心类以支持两个类之间的多对多关系,但这些类和关系的数组/数据来自2个或更多数据源 也就是说,如果我们有一个简单的关系,比如:Asp.net core 实体框架核心存储来自多个数据源的多对多关系,asp.net-core,.net-core,entity-framework-core,Asp.net Core,.net Core,Entity Framework Core,如何正确实现实体框架核心类以支持两个类之间的多对多关系,但这些类和关系的数组/数据来自2个或更多数据源 也就是说,如果我们有一个简单的关系,比如: public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public List<PostTag> PostTags {
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
公共类职位
{
公共int PostId{get;set;}
公共字符串标题{get;set;}
公共字符串内容{get;set;}
公共列表PostTags{get;set;}
}
公共类标签
{
公共字符串TagId{get;set;}
公共列表PostTags{get;set;}
}
公共类PostTag
{
公共int PostId{get;set;}
公共Post Post{get;set;}
公共字符串TagId{get;set;}
公共标记{get;set;}
}
我们的服务器将通过一个web api从两个或多个数据源获取一系列帖子、标签以及它们之间的任何关系。因此,如果我们只是简单地尝试直接获取数据并将其序列化回数据库,那么在给定2个或更多不同源的情况下,会与Id键发生冲突。存储同一类结构的不同源以及不丢失关系信息的正确方法是什么?谢谢您缺少的是转换层。让我解释一下 存储在数据库中的post对象必须具有以下结构: Post表
- PostId-这是您自己表中的主键。自动生成,必需
- ExternalPostId—这是从API到达的PostId
- 标题-这是从API到达的标题
- 内容-这是从API到达的内容
- TagId-这是您自己的标记表的主键。自动生成,必需
- ExternalTagId-这是从API到达的TagId
- OtherField1、OtherField2-任何其他字段都会与API中的标记一起到达
- PostId,TagId-复合主键
- PostId-外键,必填,非自动编号,参考
表Post
- TagId-外键,必需,非自动编号,参考
表标记
public class Database : DbContext {
public virtual DbSet<DbPost> Posts { get; set; }
public virtual DbSet<DbTag> Tags { get; set; }
public virtual DbSet<DbPostTag> PostTags { get; set; }
...
}
如果您在单独的调用中接收post、post标记和标记,则插入操作会有所不同:
var insertedPosts = new List<DbPost>();
var insertedTags = new List<DbTag>();
foreach(var post in posts){
var dbPost = post.ToDbPost();
Database.Posts.Add(dbPost);
insertedPosts.Add(dbPost);
}
foreach(var tag in tags){
var dbTag = tag.ToDbTag();
Database.Tags.Add(dbTag);
insertedTags.Add(dbTag);
}
Database.SaveChanges();
最后一项是当您检索回数据时,您希望它以原始格式显示。
以下查询将返回所有帖子、它们的链接实体和它们的标记:
var dbPosts = this.Database.Posts
.Include( p => p.PostTags )
.ThenInclude(pt => pt.Tag )
.ToList();
var apiPosts = dbPosts.Select(p => p.ToApiPost()).ToList();
要将内容转换回原始的Post、PostTag和标记类型,只需创建如下扩展方法:
public static class DbObjectExtensions {
public static Post ToApiPost(this DbPost dbPost){
var post = new Post(){
PostId = dbPost.ExternalId,
Title = dbPost.Title,
Content = dbPost.Content,
PostTags = new List<PostTag>()
};
if(dbPost.PostTags != null) {
foreach(var dbPostTag in dbPost.PostTags){
if(dbPostTag.Tag != null){
var tag = dbPostTag.Tag.ToApiTag();
var postTag = new PostTag(){
PostId = post.PostId,
Post = post,
TagId = tag.TagId,
Tag = tag
};
post.PostTags.Add(postTag);
tag.PostTags.Add(postTag);
}
}
}
return post;
}
public static Tag ToApiTag(this DbTag dbTag){
return new Tag(){
TagId = dbTag.ExternalId
};
}
}
公共静态类DbObjectExtensions{
公共静态Post到PIPOST(此DbPost){
var post=new post(){
PostId=dbPost.ExternalId,
Title=dbPost.Title,
Content=dbPost.Content,
PostTags=新列表()
};
if(dbPost.PostTags!=null){
foreach(dbPost.PostTags中的var dbPostTag){
if(dbPostTag.Tag!=null){
var tag=dbPostTag.tag.ToApiTag();
var postTag=new postTag(){
posted=post.posted,
Post=Post,
TagId=tag.TagId,
标签=标签
};
post.PostTags.Add(postTag);
tag.PostTags.Add(postTag);
}
}
}
回程站;
}
公共静态标记ToApiTag(此DbTag DbTag){
返回新标记(){
TagId=dbTag.ExternalId
};
}
}
这是一个相当广泛的问题。事实上,你在问:我如何处理并发?我认为Post
应该包含List
而不是List
@viveknuna不,EF-core不支持那种多对多关系。@GertArnold我在想做一些类似的事情:public-class-repost:Post{[Key]public-int-Id{get;set;}这种方法可以添加一个额外的Id键作为实际的DB键,然后修复导入的数据和关系,但如果您有多对多关系,这似乎是不可能的。看看下面的答案。
[Table("Tag")
public class DbTag
{
[Key]
[Column("TagId")]
public int Id { get; set; }
[Column("ExternalTagId")]
public string ExternalId { get; set; }
public IList<PostTag> PostTags { get; set; }
}
public class DbPostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public int TagId { get; set; }
public Tag Tag { get; set; }
}
public class Database : DbContext {
public virtual DbSet<DbPost> Posts { get; set; }
public virtual DbSet<DbTag> Tags { get; set; }
public virtual DbSet<DbPostTag> PostTags { get; set; }
...
}
public static class ApiObjectExtensions {
public static DbPost ToDbPost(this Post post){
var dbPost = new DbPost(){
ExternalId = post.PostId,
Title = post.Title,
Content = post.Content,
PostTags = new List<DbPostTags>()
};
}
public static DbTag ToDbTag(this Tag tag){
return new DbTag(){
ExternalId = tag.Id,
PostTags = new List<DbPostTags>()
};
}
}
foreach(var post in posts){
var dbPost = post.ToDbPost();
if(post.PostTags != null && post.PostTags.Any()){
foreach(var postTag in post.PostTags){
if(postTag.Tag != null){
var dbTag = postTag.Tag.ToDbTag();
var dbPostTag = new DbPostTag(){
Post = dbPost,
Tag = dbTag
};
dbPost.PostTags.Add(dbPostTag);
}
}
}
Database.DbPosts.Add(dbPost);
}
Database.SaveChanges();
var insertedPosts = new List<DbPost>();
var insertedTags = new List<DbTag>();
foreach(var post in posts){
var dbPost = post.ToDbPost();
Database.Posts.Add(dbPost);
insertedPosts.Add(dbPost);
}
foreach(var tag in tags){
var dbTag = tag.ToDbTag();
Database.Tags.Add(dbTag);
insertedTags.Add(dbTag);
}
Database.SaveChanges();
foreach(var postTag in postTags){
var dbPost = insertedPosts.FirstOrDefault(p => p.ExternalId = postTag.PostId);
var dbTag = insertedTags.FirstOrDefault(t => t.ExternalId = postTag.TagId);
if(dbPost != null && dbTag != null){
var dbPostTag = new DbPostTag(){
PostId = dbPost.Id,
Tag = dbTag.Id
};
Database.PostTags.Add(dbPostTag);
}
}
Database.SaveChanges();
var dbPosts = this.Database.Posts
.Include( p => p.PostTags )
.ThenInclude(pt => pt.Tag )
.ToList();
var apiPosts = dbPosts.Select(p => p.ToApiPost()).ToList();
public static class DbObjectExtensions {
public static Post ToApiPost(this DbPost dbPost){
var post = new Post(){
PostId = dbPost.ExternalId,
Title = dbPost.Title,
Content = dbPost.Content,
PostTags = new List<PostTag>()
};
if(dbPost.PostTags != null) {
foreach(var dbPostTag in dbPost.PostTags){
if(dbPostTag.Tag != null){
var tag = dbPostTag.Tag.ToApiTag();
var postTag = new PostTag(){
PostId = post.PostId,
Post = post,
TagId = tag.TagId,
Tag = tag
};
post.PostTags.Add(postTag);
tag.PostTags.Add(postTag);
}
}
}
return post;
}
public static Tag ToApiTag(this DbTag dbTag){
return new Tag(){
TagId = dbTag.ExternalId
};
}
}