点燃对非匿名类型的 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});