Bug in LLBLGen Linq

Posts   
 
    
hotchill avatar
hotchill
User
Posts: 180
Joined: 22-Jan-2007
# Posted on: 16-Jul-2019 10:47:08   

Hi.

I am using llblgen v5.5.4 (build 06-jul-2019) with adapter.

There is a bug in llblgen linq, at least it is different from .net linq.

All the users selected here get the same list (same object) in their Tenants property.

var metadata = new LinqMetaData(adapter); _usersHashedById = metadata.User.Select(u => new UserForAttributeCalculation { DepartmentRoleId = u.DepartmentRoleId, Login = u.Login, Tenants = new List<TenantEntity>(), EndDate = u.EndDate }).ToDictionary(u => u.UserId);

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 16-Jul-2019 16:09:36   

This is unavoidable, sadly. We replace the database related elements in the lambda with fetches from the datareader and leave the rest, then compile the lambda and use that to create new instances for each row from the datareader. So your lambda becomes:


row, indexes => 
    new UserForAttributeCalculation {
    DepartmentRoleId = row[indexes[0]],
    Login = row[indexes[1]],
    Tenants = new List<TenantEntity>(),
    EndDate = row[indexes[2]]
}

This means that the code inside the lambda that runs in-memory isn't interpreted. I.e. we don't analyze what's there as it can in theory be a big piece of in-memory code and we then have to analyze everything and interpret what the analyzer sees and then act accordingly.

What I suspect is that the .NET clr/jit optimizes this per-lambda instance, as we cache the lambda, so we re-use it for the same query and for each row. Frankly I don't know why it doesn't work as all we do is simply execute the compiled lambda so it should create a new list every time.

A workaround might be:

[MethodImpl(MethodImplOptions.NoInlining)]
private List<T> CreateEmptyEntityList<T>() => new List<T>();

And instead of new List<TenantEntity>(), use a call to this method.


var metadata = new LinqMetaData(adapter);
_usersHashedById = metadata.User.Select(u =>
    new UserForAttributeCalculation {
    DepartmentRoleId = u.DepartmentRoleId,
    Login = u.Login,
    Tenants = CreateEmptyEntityList<TenantEntity>(),
    EndDate = u.EndDate
}).ToDictionary(u => u.UserId);

Frans Bouma | Lead developer LLBLGen Pro
hotchill avatar
hotchill
User
Posts: 180
Joined: 22-Jan-2007
# Posted on: 16-Jul-2019 23:15:40   

Thanks Frans simple_smile