I'll start from afar a little. My task is to copy all tables from legacy database to antoher db. The tables of this database were not created by me and it was a long time ago. That's why paginations I use to copy these tables differ a little. First pagination I use works fine. I filter entities using Expression trees and it works with good performance. The code is below.
var parameter = Expression.Parameter(typeof(TDbSet));
var property = Expression.Property(parameter, primaryKeyProperty.Name);
var body = Expression.GreaterThan(property,Expression.Constant(id, typeof(TId)));
entities = await _dbFirst.Set<TDbSet>().AsNoTracking()
.Where(Expression.Lambda<Func<TDbSet, bool>>(body, parameter))
.Take(PAGE_SIZE)
.ToListAsync()
.ConfigureAwait(false);
Now is the problem. Class for copying table works with generic type parameter TId. For tables with composite PK I take one PK type, and then Select all its Ids through TDbSet (you better look the code below and you'll understand what I am talking about). By these distinct list of id's I take entities from one DB and copy them to another DB. I don't know how to use SELECT operation with Expression trees. That's why I take Id's value by type. It takes 5seconds every time I take them, it is very bad performance because table can contain millions of rows.
var allPkIds = _dbFirst.Set<TDbSet>().AsNoTracking()
.Select(e => e.GetType().GetProperty(primaryKeyProperty.Name).GetValue(e))
.Distinct()
.OrderBy(o => o)
.Skip(alreadyTakenIdsCounter)
.Take(COMMIT_SIZE_FOR_COMPOSITE_PK)
.ToArray();
alreadyTakenIdsCounter = COMMIT_SIZE_FOR_COMPOSITE_PK;
foreach (var entityId in allPkIds)
{
var body = Expression.Equal(property, Expression.Constant(entityId));
var entities = await _dbFirst.Set<TDbSet>().AsNoTracking()
.Where(Expression.Lambda<Func<TDbSet, bool>>(body, parameter))
.ToListAsync()
.ConfigureAwait(false);
Now is the question. How can I use Expression.Lambda for such select operation? I googled a lot and read Microsoft documentation but I can't find answer.
CodePudding user response:
Try the following:
var param = Expression.Parameter(typeof(TDbSet), "e");
var selectLambda = Expression.Lambda<Func<TDbSet, TId>>(
Expression.MakeMemberAccess(param, primaryKeyProperty), param);
var allPkIds = _dbFirst.Set<TDbSet>().AsNoTracking()
.Select(selectLambda)
.Distinct()
.OrderBy(o => o)
.Skip(alreadyTakenIdsCounter)
.Take(COMMIT_SIZE_FOR_COMPOSITE_PK)
.ToArray();