当前位置: 首页 > 编程语言 > C#

如何通过分配新集合来更新多对多集合?Share

时间:2023-04-11 02:08:57 C#

如何通过分配新集合来更新多对多集合?在entityframeworkcore2.0中,Post和Category之间有很多关系(绑定类是PostCategory)。当用户更新Post时,整个Post对象(及其PostCategory集合)将被发送到服务器,我想在服务器上重新分配新收到的CollectionPostCategory(用户可以通过添加新类别和删除某些类别来显着更改此Collection).我用来更新该集合的简化代码(我只是分配了全新的集合):post.PostCategories=...一些新的收藏...;//<<p.Comments).Include(p=>p.PostCategories).ThenInclude(pc=>pc.Category).Include(p=>p.PostPackages).ThenInclude(pp=>pp.Package)//.AsNoTracking().SingleOrDefaultAsync(p=>p.Id==postId);更新3(我的控制器中的代码,它试图更新帖子):varwriterId=User.GetUserId();varcategories=awaitpostService.GetOrCreateCategoriesAsync(vm.CategoryViewModels.Select(cvm=>cvm.Name),writerId);varpost=awaitpostService.GetPostAsync(vm.PostId);post.Title=vm.PostTitle;post.Content=vm.ContentText;post.PostCategories=categories?.Select(c=>newPostCategory{CategoryId=c.Id,PostId=post.Id}).ToArray();等待postService.UpdatePostAsync(post);//检查t他在Update4中实现。更新4:publicasyncTaskUpdatePostAsync(Postpost){//查找(从数据库加载)现有帖子varexistingPost=awaitdbContext.Posts.SingleOrDefaultAsync(p=>p.Id==post.Id);//应用原始属性修改dbContext.Entry(existingPost).CurrentValues.SetValues(post);//应用多对多链接修改dbContext.Set().UpdateLinks(pc=>pc.PostId,post.Id,pc=>pc.CategoryId,post.PostCategories.Select(pc=>pc.CategoryId));//将所有更改应用于数据库awaitdbContext.SaveChangesAsync();返回现有帖子;使用断开连接的实体时的主要挑战是检测和应用添加和删除的链接,而EFCore(在撰写本文时)提供的帮助很少甚至没有。链接的答案是可以的(自定义Except方法对于它的IMO来说太重了),但它有一些缺陷-必须使用急切/显式加载来尽早检索现有链接(尽管EFCore2.1延迟加载可能不是问题),以及新链接应该只填充FK属性-如果它们包含引用导航属性,EFCore将在调用Add/AddRange时尝试创建新的链接实体。前段时间我回答了一个类似但略有不同的问题-更新EFCore连接的通用方法。以下是答案中更通用和优化的自定义通用扩展方法版本:publicstaticclassEFCoreExtensions{publicstaticvoidUpdateLinks(thisDbSetdbSet,Expression>fromIdProperty,TFromIdfromId,Expression>toIdProperty,IEnumerabletoIds)wherenewTLink:class(){//链接=>link.FromId==fromId表达式>fromIdVar=()=>fromId;varfilter=Expression.Lambda>(Expression.Equal(fromIdProperty.Body,fromIdVar.Body),fromIdProperty.Parameters);varexistingLinks=dbSet.AsTracking().Where(过滤器);vartoIdSet=newHashSet(toIds);if(toIdSet.Count==0){//新集合为空——删除所有存在的链接dbSet.RemoveRange(existingLinks);返回;}//删除新集合中不存在的现有链接vartoIdSelector=toIdProperty.Compile();foreach(varexistingLinkinexistingLinks){if(!toIdSet.Remove(toIdSelector(existingLink)))dbSet.Remove(existingLink);}//为新集合中的剩余项创建新链接if(toIdSet.Count==0)return;//toId=>newTLink{FromId=fromId,ToId=toId}vartoIdParam=Expression.Parameter(typeof(TToId),"toId");varcreateLink=Expression.Lambda>(Expression.MemberInit(Expression.New(typeof(TLink)),Expression.Bind(((MemberExpression)fromIdProperty.Body).Member,fromIdVar.Body),Expression.Bind(((MemberExpression)toIdProperty.Body).Member,toIdParam)),toIdParam);dbSet.AddRange(toIdSet.Select(createLink.Compile()));它使用单个数据库查询从数据库中检索退出链接。开销是非常少的动态构建的表达式和编译的委托(以保持调用代码尽可能简单)和一个临时的HashSet用于快速查找。表达式/委托构建的性能影响应该可以忽略不计,并且可以根据需要进行缓存。这个想法是只为一个链接实体传递一个现有密钥,为另一个链接实体传递一个退出密钥列表。因此,根据您要更新的链接实体链接,它的调用方式会有所不同。在您的示例中,假设您收到一个IEnumerablepostCategories,过程将是这样的:varpost=awaitdbContext.Posts.SingleOrDefaultAsync(someId);dbContext.Set().UpdateLinks(pc=>pc.PostId,post.Id,pc=>pc.CategoryId,postCategories.Select(pc=>pc.CategoryId));等待dbContext.SaveChangesAsync();请注意,此方法允许您更改请求并接受IEnumerablepostCategoryIds:dbContext.Set().UpdateLinks(pc=>pc.PostId,post.Id,pc=>pc.CategoryId,postCategoryIds);或IEnumerablepostCategories:dbContext.Set().UpdateLinks(pc=>pc.PostId,post.Id,pc=>pc.CategoryId,postCategories.Select(c=>c.Id));或类似的DTO/ViewModel。类别帖子可以以类似的方式更新,并交换相应的选择器。UPDATE:如果你收到一个(可能)修改过的Post实体实例,整个更新过程如下://查找(从数据库加载)现有的postvarexistingPost=awaitdbContext.Posts.SingleOrDefaultAsync(p=>p.Id==post.Id);if(existingPost==null){//处理无效调用return;}//应用原始属性修改dbContext.Entry(existingPost).CurrentValues.SetValues(post);//应用多对多链接修改dbContext.Set().UpdateLinks(pc=>pc.PostId,post.Id,pc=>pc.CategoryId,post.PostCategories.Select(pc=>pc.CategoryId));//将所有更改应用于数据库awaitdbContext.SaveChangesAsync();请注意,EFCore使用单独的数据库查询来预加载相关集合。由于helper方法执行相同的操作,因此在从数据库中检索主要实体时不??需要包含链接相关数据。以上就是C#学习教程:HowtoupdateCollectioninMany-ManybyassigninganewCollection?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: