Trying to write an ExpressionVisitor that would rewrite a query
Starting point
var contractSubjectKey = new ContractSubjectKey(subjectId, rank);
insurance = context.Set<Insurance>()
.FirstOrDefault(i => i.Key.ContractSubjectKey == contractSubjectKey);
After rewrite expected
i => i.Key.ContractSubjectKey.Id == contractSubjectKey.Id
I’m trying to rewrite BinaryExpression
here so it goes and compares properties itself.
The left side of operation I think i got covered. Initial left side of BinaryExpression
is MemberExpression
.
var left = Expression.Property(memberExpression, "Id");
So I just access property itself.
In case i use for right side ConstantExpression
var right = Expression.Constant(1, typeof(int));
so the resulting operation looks like
i.Key.ContractSubjectKey.Id == 1
it gets translated to SQL no problem, and retrieves data.
I do have problem with the right side. Right side is ParameterExpression
. Parameter values I cannot find anywhere in initial Expression
or QueryExpressionEventData
(working with IQueryExpressionInterceptor
). Not sure I understand it fully. It represents a local variable, evaluates during translation, something close to constant?
Anyway, if i try PropertyExpression
var right = Expression.Property(parameterExpression, "Id");
it seems i get proper looking expression, but during translation it fails
`The Linq expression …. could not be translated
System.InvalidOperationException : The LINQ expression ‘DbSet()
.Where(i => EF.Property(EF.Property(i, “Key”), “ContractSubjectKey”).Id == __contractSubjectKey_0.Id)’ could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to ‘AsEnumerable’, ‘AsAsyncEnumerable’, ‘ToList’, or ‘ToListAsync’.
So problem is somewhere in evaluation value for Id
on local variable?
Tried many things… not gonna waste space here.
One additional piece of context
public record ContractSubjectKey(int Id, int Rank);
//insurance.Key.ContractSubjectKey is actually ContractSubjectKeyInsurance which inherits from ContractSubjectKey
public record ContractSubjectKeyInsurance : ContractSubjectKey
{
public ContractSubjectKeyInsurance(int Id, int Rank) : base(Id, Rank)
{
}
public ContractSubjectKeyInsurance(int Id, int Rank, int InsuranceKeyId) : base(Id, Rank)
{
_insuranceKeyId = InsuranceKeyId;
}
private int _insuranceKeyId;
}
public record InsuranceKey(int Id, ContractSubjectKey ContractSubjectKey)
{
this.Id = Id;
_contractSubjectId = ContractSubjectKey.Id;
_contractSubjectRank = ContractSubjectKey.Rank;
this.ContractSubjectKey =
new ContractSubjectKeyInsurance(ContractSubjectKey.Id, ContractSubjectKey.Rank, Id);
}