Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding entities using AddRange method does not refresh entity ID

I am using EF Core 1.1.1. I have noticed when i add IEnumerable<Entity> using AddRange method and then call SaveChanges() then entities gets saved in the database however their ID does not get refreshed.

Code below does not refresh ID after SaveChanges(). Note i am passing requests as IEnumerable

    public async Task Post([FromBody]IEnumerable<string> values)
    {
        var requests = values.Select(x => new Test()
        {
            Name = x,
            Status = "Init"
        });

        await _dbContext.Tests.AddRangeAsync(requests).ConfigureAwait(false);
        await _dbContext.SaveChangesAsync().ConfigureAwait(false);

        foreach (var r in requests)
        {
            var id = r.ID;
        }
    }

Code below does not refresh ID after SaveChanges(). Note i am passing request.ToList() as a parameter to AddRange method

    public async Task Post([FromBody]IEnumerable<string> values)
    {
        var requests = values.Select(x => new Test()
        {
            Name = x,
            Status = "Init"
        });

        await _dbContext.Tests.AddRangeAsync(requests.ToList()).ConfigureAwait(false);
        await _dbContext.SaveChangesAsync().ConfigureAwait(false);

        foreach (var r in requests)
        {
            var id = r.ID;
        }
    }

Code below does refresh ID after SaveChanges(). Note I am calling ToList() after selecting values.

    public async Task Post([FromBody]IEnumerable<string> values)
    {
        var requests = values.Select(x => new Test()
        {
            Name = x,
            Status = "Init"
        }).ToList();   //<------ ToList() or ToArray() would work

        await _dbContext.Tests.AddRangeAsync(requests).ConfigureAwait(false);
        await _dbContext.SaveChangesAsync().ConfigureAwait(false);

        foreach (var r in requests)
        {
            var id = r.ID;
        }
    }

I am not sure if this is a bug in EF or this is how it supposed to work. I understand IEnumerable is lazy and List and Array are eager, but if AddRange method is taking IEnumerable as parameter then it should work regardless.

like image 684
LP13 Avatar asked Mar 31 '17 18:03

LP13


1 Answers

As Ivan states the reason you are not seeing the id's is that in the Non working cases you are enumerating new test objects.

If you place a break point inside the enumerable you will see that during your for each it creates new Test objects at that time. These are NOT the same objects that were place in the database.

You are actually enumerating the IEnumerable twice

public async Task Post([FromBody]IEnumerable<string> values)
{
    var requests = values.Select(x => { 
        
        //place break point here
        new Test()
        {
            Name = x,
            Status = "Init"
        }
    });

    await _dbContext.Tests.AddRangeAsync(requests.ToList()).ConfigureAwait (false);
    await _dbContext.SaveChangesAsync().ConfigureAwait(false);

    foreach (var r in requests)
    {
        var id = r.ID;
    }
}
like image 119
drowhunter Avatar answered Oct 22 '22 11:10

drowhunter