Update an already tracked entities

entity-framework-core

Question

I want to update the itemsToUpdate collection. This collection is already used in a query thus the resulting entities are already tracked in the context local property.

What is the most efficient way of overriding properties of the context.items.Local property from the itemsToUpdate collection?

private async Task<IEnumerable<item>> GetitemsAsync(IEnumerable<item> itemIds)
            {
                return await context.items.Where(t => itemIds.Select(x => x.Id).Contains(t.Id)).ToListAsync();
            }

public async Task Update(...)
{
            // Update
            var queryUpdateitems = await GetitemsAsync(itemsToUpdate);

            bool canUpdate = queryUpdateitems.All(t => t.UserId == userId);
            if (!canUpdate)
            {
                throw new NotAuthorizedException();
            }
            else
            {
               // update here the itemsToUpdate collection
            }

            context.SaveChangesAsync();
}
1
0
7/13/2017 9:18:37 PM

Accepted Answer

In your case, you know that you have to update all these items, you just want to make sure that current user can update all items (by comparing Item.UserId). Instead of fetching all the existing items from database to make the check, you can query database to give result of the check and then you can just send update to database if check is true.

var itemIds = itemsToUpdate.Select(x => x.Id).ToList();
var canUpdate = await db.Blogs.Where(b => itemIds.Contains(b.Id)).AllAsync(t => t.UserId == userId);
if (canUpdate)
{
    db.UpdateRange(itemsToUpdate);
}
else
{
    throw new NotSupportedException();
}

await db.SaveChangesAsync();

Here, you have to make list of itemIds first because EF cannot inline list of items in a query and will do evaluation on client otherwise. That means EF is fetching whole table. Same is true for your GetitemsAsync method. It also queries whole table. Consider creating itemIds locally in that method too.

Once you pass in List<int> in the method EF will be happy to inline it in query and for query of canUpdate it will sent single query to database and fetch just true/false from database. Then you can use UpdateRange directly since there are nomore tracking records. Since it does not fetch all items from database, it will be faster too.

0
7/14/2017 7:43:00 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow