点燃对非匿名类型的 LINQ 提供程序投影支持
Ignite LINQ provider projection support for non-anonymous types
我正在尝试在我的 LINQ 查询中使用投影,在 https://www.gridgain.com/docs/latest/developers-guide/net-specific/net-linq 上找到以下示例:
var query = ignite.GetCache<EmployeeKey, Employee>(CacheName).AsCacheQueryable().Where(emp => emp.Value.IsIntern);
...
var custom = query.Select(emp => new {Id = emp.Key, Name = emp.Value.Name, Age = emp.Value.Age});
目前似乎只支持 C# 匿名类型。我尝试使用下面的查询,但它们因 NotSupportedException:
而失败
var query = ignite.GetCache<EmployeeKey, Employee>(CacheName).AsCacheQueryable().Where(emp => emp.Value.IsIntern);
...
var custom1 = query.Select(emp => new Employee { Id = emp.Key, Name = emp.Value.Name, Age = emp.Value.Age});
var custom2 = query.Select(emp => new Employee(emp.Key, emp.Value.Name, emp.Value.Age));
是否有计划在 select 方法中支持 类?什么时候可以使用此功能?
PS:使用构造函数调用的 Select 投影实际上有效,但您不能在 Select 方法之后使用 Where 子句。我已经从 Apache.Ignite.Examples:
更新了 ThinClientSqlExample.LinqExample 方法
IQueryable<Employee> query = cache.AsCacheQueryable()
.Select(emp => emp.Value)
.Select(emp => new Employee(emp.Name, emp.Salary, emp.Address, null, null))
.Where(emp => emp.Salary > 0);
并收到异常:
System.NotSupportedException: 'Expression not supported: new Employee([emp].Value.Name, [emp].Value.Salary, [emp].Value.Address, null).Salary'
对 Apache 进行了大量调试。Ignite/Remote.Linq 并找到了一个解决方法来支持 Select 之后使用构造函数调用 Where 方法:
public class SetNewExpressionMembersVisitor : ExpressionVisitor
{
protected override Expression VisitNew(NewExpression node)
{
var constructorParameters = node.Constructor.GetParameters();
var typeMembers = node.Type.GetMembers();
var constructorMembers = new MemberInfo[constructorParameters.Length];
for (int i = 0; i < constructorParameters.Length; i++)
{
var parameter = constructorParameters[i];
var member = typeMembers.FirstOrDefault(x => string.Compare(x.Name, parameter.Name, true) == 0);
if (member == null)
{
throw new NullReferenceException($"Unable to find member of type '{node.Type.FullName}' for '{parameter.Name}' constructor parameter");
}
constructorMembers[i] = member;
}
return Expression.New(node.Constructor, node.Arguments, constructorMembers);
}
}
query.Select(emp => new Employee(emp.Key, emp.Value.Name, emp.Value.Age));
构造函数调用预测应该有效,你能仔细检查一下吗?它适用于最近的 Ignite 版本 (2.8+)。
query.Select(emp => new Employee(emp.Key, emp.Value.Name...
不支持MemberInit projections,我已经提交了一个ticket,你可以在下一个版本中期待它。
作为解决方法,使用中间匿名类型投影:
var custom1 = query.Select(emp => new { Id = emp.Key, Name = emp.Value.Name})
.AsEnumerable()
.Select(emp => new Employee { Id = emp.Id, Name = emp.Name});
我正在尝试在我的 LINQ 查询中使用投影,在 https://www.gridgain.com/docs/latest/developers-guide/net-specific/net-linq 上找到以下示例:
var query = ignite.GetCache<EmployeeKey, Employee>(CacheName).AsCacheQueryable().Where(emp => emp.Value.IsIntern);
...
var custom = query.Select(emp => new {Id = emp.Key, Name = emp.Value.Name, Age = emp.Value.Age});
目前似乎只支持 C# 匿名类型。我尝试使用下面的查询,但它们因 NotSupportedException:
而失败var query = ignite.GetCache<EmployeeKey, Employee>(CacheName).AsCacheQueryable().Where(emp => emp.Value.IsIntern);
...
var custom1 = query.Select(emp => new Employee { Id = emp.Key, Name = emp.Value.Name, Age = emp.Value.Age});
var custom2 = query.Select(emp => new Employee(emp.Key, emp.Value.Name, emp.Value.Age));
是否有计划在 select 方法中支持 类?什么时候可以使用此功能?
PS:使用构造函数调用的 Select 投影实际上有效,但您不能在 Select 方法之后使用 Where 子句。我已经从 Apache.Ignite.Examples:
更新了 ThinClientSqlExample.LinqExample 方法 IQueryable<Employee> query = cache.AsCacheQueryable()
.Select(emp => emp.Value)
.Select(emp => new Employee(emp.Name, emp.Salary, emp.Address, null, null))
.Where(emp => emp.Salary > 0);
并收到异常:
System.NotSupportedException: 'Expression not supported: new Employee([emp].Value.Name, [emp].Value.Salary, [emp].Value.Address, null).Salary'
对 Apache 进行了大量调试。Ignite/Remote.Linq 并找到了一个解决方法来支持 Select 之后使用构造函数调用 Where 方法:
public class SetNewExpressionMembersVisitor : ExpressionVisitor
{
protected override Expression VisitNew(NewExpression node)
{
var constructorParameters = node.Constructor.GetParameters();
var typeMembers = node.Type.GetMembers();
var constructorMembers = new MemberInfo[constructorParameters.Length];
for (int i = 0; i < constructorParameters.Length; i++)
{
var parameter = constructorParameters[i];
var member = typeMembers.FirstOrDefault(x => string.Compare(x.Name, parameter.Name, true) == 0);
if (member == null)
{
throw new NullReferenceException($"Unable to find member of type '{node.Type.FullName}' for '{parameter.Name}' constructor parameter");
}
constructorMembers[i] = member;
}
return Expression.New(node.Constructor, node.Arguments, constructorMembers);
}
}
query.Select(emp => new Employee(emp.Key, emp.Value.Name, emp.Value.Age));
构造函数调用预测应该有效,你能仔细检查一下吗?它适用于最近的 Ignite 版本 (2.8+)。
query.Select(emp => new Employee(emp.Key, emp.Value.Name...
不支持MemberInit projections,我已经提交了一个ticket,你可以在下一个版本中期待它。
作为解决方法,使用中间匿名类型投影:
var custom1 = query.Select(emp => new { Id = emp.Key, Name = emp.Value.Name})
.AsEnumerable()
.Select(emp => new Employee { Id = emp.Id, Name = emp.Name});