Delete records with multiple ids based on condition

匿名 (未验证) 提交于 2019-12-03 09:06:55

问题:

Below is my class :

 public partial class Ads     {        public int Id { get; set; }        public int RegionId { get; set; }        public string Name { get; set; }        public int Group { get; set; }     } 

Records :

Id      Name   Group 1       abc     1 2       xyz     1 3       lmn     1 4       xxx     2 5       ppp     2 6       ttt     3 7       ggg     3 

Now I want to remove all records/only that record with particular id of same group for some ids.

Code :

public void Delete(int[] ids,bool flag = false)         {             using (var context = new MyEntities())             {                 context.Ads.RemoveRange(                     context.Ads.Where(t => (flag ?                    (context.Ads.Any(x => ids.Contains(x.Id) && x.Group == t.Group)) : false)));                 context.SaveChanges();             }         } 

What I am trying to do is something like below :

If flag is false with ids=3,5 then     I want to delete only records with Id=3,5 Else if flag is true with ids=3,5 then     I want to delete records with Id=3,5 but all other records too of the group to which ids=3,5 belong to.     Here id=3 belongs to group 1 so I want to delete all records of group1 i.e id=1,2 like wise ids=5 belongs to     group 2 so I want to delete all records of group 2 i.e id=4. 

Expected output for this last case(flag=true) :

Id      Name   Group 6       ttt     3 7       ggg     3 

But I think that I haven't done this is a proper way, and there is some source of improvement in the query.

Note : ids[] will always contains ids from different group and that too highest ids from different group.

How can I to improve my query for both the cases(flag=true and false)?

回答1:

What about

var removeRecs=context.Ads.where(t => ids.contains(t.id)) if(flag) removeRecs.AddRange(context.Ads.where(t=> removeRecs.Any(r =>t.groupId==r.Id))) Ads.RemoveRange(removeRecs); 


回答2:

Do not make it too hard for your self, not everything must/can be done in the where statement of a query. Also a general rule of thumb in a loop try to factor out all the constant values and checks. So try this:

    public static void Delete(int[] ids, bool flag = false)     {         using (var context = new MyEntities())         {             var query = context.Ads.AsQueryable();             query = flag               ? query.Where(x => context.Ads                                    .Where(i => ids.Contains(i.Id))                                    .Select(i => i.Group)                                    .Contains(x.Group))               : query.Where(x => ids.Contains(x.Id));              context.Ads.RemoveRange(query);             context.SaveChanges();         }     } 


回答3:

 public void Delete(int[] ids, bool flag = false)         {             using (var context = new MyEntities())             {                 var items = context.Ads.Where(x => ids.Any(a => x.Id == a));                   if (!flag)                 {                     //flag=false --> delete items with Id in ids[]                     context.Ads.RemoveRange(items);                 }                 else                 {                     var groups = items.GroupBy(a => a.Group).Select(a => a.Key);                      //flag=true --> delete all items in selected groups                     context.Ads.RemoveRange(context.Ads.Where(x => groups.Any(a => x.Group == a)));                 }                 context.SaveChanges();             } 


回答4:

You should separate your tasks...

if (flag) {     groupIds = db.Ads.Where(x => ids.Contains(x.Id)).Select(x => x.Group).ToList();     db.Ads.RemoveRange(db.Ads.Where(x => groupIds.Contains(x.Group)).ToList()); } else {     db.Ads.RemoveRange(db.Ads.Where(x => ids.Contains(x.Id)).ToList()); } 


回答5:

To me it looks like you have two different deletes here.

In first case you are only deleting the ads with given ID and this is pretty straight forward.

In second case you are deleting the ads with given ID and all other ads that contain the group of the recently deleted Ads. So in this case instead of deleting the ads with given Id first why not actualy get distinct groups for these ID-s and than just delete the groups.

EDIT

You can do it like this.

using (var context = new TestEntities()) {     if (!flag)         context.Ads.RemoveRange(context.Ads.Where(a => ids.Contains(a.Id)));     else         context.Ads.RemoveRange(context.Ads.Where(a => context.Ads.Where(g => ids.Contains(g.Id)).Select(x => x.Group).Distinct().Contains(a.Group)));     context.SaveChanges(); } 

For the more complicated case I am trying to get distinct groups for given id-s. So for ID-s 3 and 5 I am selecting the groups and than I am doing distinct on the groups since it might happen that the id-s have the same group. Than I am fetching all the ads that have these groups. So for passed values of 3 and 5 I would get groups 1 and 2 which I would than use to get all the ads that have that group. That in turn would yield id-s 1, 2, 3, 4, and 5 which I would than delete.

EDIT 2

If the complexity of second Linq query bothers you than write a SQL query.

context.Database.ExecuteSqlCommand(          "DELETE Ads WHERE Group IN (SELECT Group FROM Ads WHERE Id IN(@p1, @p2))", new SqlParameter("@p1", ids[0]), new SqlParameter("@p2", ids[1]));  

This should be extra performant rather than rely on EF which will delete it one by one.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!