为什么IQueryable.Select每次迭代都使用相同的引用

时间:2018-10-12 14:00:26

标签: c# entity-framework linq .net-core iqueryable

我有一个要执行IQueryable的{​​{1}}。在该选择中,我创建一个对象的新实例并运行一个函数,该函数将对象的值从IQueryable(b)复制到新创建的对象(新DTO),然后返回该实例。

IQueryable。选择:

Select

DTO中的功能

businessLayer.GetAll().Select( b => new DTO().InitInhertedProperties(b)).ToList();

复制功能

public DTO InitInhertedProperties(Base baseInstance)
{
    return Utilities.InitInhertedProperties(this, baseInstance);
}

第一次将public static T InitInhertedProperties<T,K>(T instance, K baseClassInstance) where T : K { foreach (PropertyInfo propertyInfo in baseClassInstance.GetType().GetProperties()) { object value = propertyInfo.GetValue(baseClassInstance, null); if (null != value) propertyInfo.SetValue(instance, value, null); } return instance; } 方法称为InitInhertedProperties是一个空对象时,instance具有应具有的值:

enter image description here

第一次迭代的结果如下: enter image description here

如您所见:一切工作都应该在第一次迭代中完成。现在是第二次迭代。

第二次baseClassInstance方法被称为InitInhertedProperties并不是一个新实例,而是第一次迭代中的一个。 insatnce就是应该的样子:

enter image description here

第二次迭代的结果如下所示: enter image description here

结果列表如下所示: enter image description here

这仅在使用baseClassInstance时发生。使用IQueryable.Select时,结果看起来与预期的一样。

这意味着可以解决此问题。但这只是解决方案,而不是解决方案。

List.Select

1 个答案:

答案 0 :(得分:2)

在使用IQueryable时,您必须绑定表达式。实体框架将检查您放入SelectOrderBy和其他方法中的每个表达式,并尝试将其转换为SQL。因此,您无法在lambda中调用仅由EF知道的任意方法

如果您想做某事,而SQL引擎没有直接支持,您可以致电AsEnumerable

businessLayer.GetAll().AsEnumerable().Select( ... 

(请注意,AsEnumerableToList好,因为它保持惰性)


可能(取决于查询提供程序的版本)可能起作用的另一个选项是手动构建表达式:

public static Expression<Func<TEntity, TDto>> InitInhertedProperties<TEntity, TDto>() where TDto : TEntity
{
    var entity = Expression.Parameter(typeof(BusinessObject), "b");
    var newDto = Expression.New(typeof(Dto).GetConstructors().First());
    var body = Expression.MemberInit(newDto,
        typeof(TDto).GetProperties()
            .Select(p => Expression.Bind(p, Expression.Property(entity, p.Name)))
      );

    return Expression.Lambda<Func<TEntity, TDto>>(body, entity);
}

用法:

var myExp = InitInhertedProperties<BusinessObject, Dto>();
var result = businessLayer.GetAll().Select(myExp).ToList();