0

I am trying to delete several records from the Locations table at once. However, I get an exception after the second pass of the foreach loop. There is also a RemoveRange method, but it takes index and count, but in this case, I don't have these parameters to use this method. How can I in this case remove several items at once from a table that is in relation one-to-many?

public async Task RemoveMultipleLocations(int id, IEnumerable<int> locationsIds)
{
   var profile = await context.AlertProfiles.Include(x => x.Locations).FirstOrDefaultAsync(x => x.Id == id);

   var existing = profile.Locations.Where(x => locationsIds.Contains(x.Id)).ToList();
   if(existing != null)
   {
         foreach(var ex in existing)
         {
              profile.Locations.Remove(ex);
         }
         profile.ModifiedDate = DateTimeOffset.Now;
         await context.SaveChangesAsync();
   }
}

RemoveRange

Serge
  • 40,935
  • 4
  • 18
  • 45
Pawlit16
  • 123
  • 2
  • 14

3 Answers3

1

If you want to delete the data from DB, I think the following code and references will be useful.

https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.dbcontext.removerange?view=efcore-5.0

How can I delete 1,000 rows with EF6?

You can edit your code this way.

public async Task RemoveMultipleLocations(int id, IEnumerable<int> locationsIds)
{
   var profile = await context.AlertProfiles.Include(x => x.Locations).FirstOrDefaultAsync(x => x.Id == id);

   var existing = profile.Locations.Where(x => locationsIds.Contains(x.Id)).ToList();
   if(existing.Any())
   {
         context.Locations.RemoveRange(existing);         
         await context.SaveChangesAsync();
   }
}

Since you have converted the" Location " list to ToList (), you do not need to check null. You can check with Any() method.

0

Try this (instead of profile.Locations use context.Locations):

var profile= await context.Profiles
                         .Include(x => x.Location)
                         .Where(x=>x.Id==id)
                         .FirstOrDefaultAsync();

var existing = profile.Locations.Where(x => locationsIds.Contains(x.Id)).ToList();
if(existing != null){
 context.Locations.RemoveRange(existing);
 context.SaveChanges();
}

Or if Location is only a navigate property:

if(existing != null)
{
foreach(var location in existing)
 context.Entry(location).State = EntityState.Deleted;
}
 context.SaveChanges();
  
            
       
Serge
  • 40,935
  • 4
  • 18
  • 45
  • I can't pass 'existing' into RemoveRange. It only accepts 'index' and 'count' as parameters, as I wrote in the question. – Pawlit16 Dec 26 '20 at 16:17
  • Sorry I don't understand why you don't have index and count. Did you try to remove range and what error did you get? – Serge Dec 26 '20 at 16:22
  • I updated the question with a screenshot (RemoveRange problem). – Pawlit16 Dec 26 '20 at 16:28
  • If I insert existing.Clear() instead of this loop (or RemoveRange), the records in the database remain unremoved. – Pawlit16 Dec 26 '20 at 16:32
0

As you have already found out, RemoveRange expects a start index and a count. But that's not difficult to obtain:

existing.RemoveRange(0, existing.Count())

you do not even need a loop, as you have already queried the records you intend to remove.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175