将 C# 表达式转换为另一个要在 EF 查询中使用的表达式
Transform a C# Expression into another Expression to be used in EF Query
在 .NET Core 应用程序中,我有如下一对多关系。
public class ModelBase
{
public virtual long Id { get; set; }
public virtual bool IsDeleted { get; set; }
}
public class Foo : ModelBase
{
public virtual string Name { get; set; }
public virtual ICollection<Bar> Bars { get; set; }
}
public class Bar : ModelBase
{
public virtual string Name { get; set; }
public virtual long FooId { get; set; }
public virtual Foo Foo { get; set; }
}
使用 EF 3.1,我需要查询 IQueryable<Bar> barQuery
,其中相应的“Foo”在逻辑上没有被删除。
由于此应用程序不使用延迟加载,我必须执行包含以在单个数据库调用中获取任何 Foo 的 属性。所以我正在尝试实现一个扩展方法,它使用单个表达式同时调用 .Include(x => x.Foo)
和 .Where(x => !x.Foo.IsDeleted)
。
到目前为止,我实现了以下扩展方法:
public static IQueryable<TEntity> IncludeNotDeleted<TEntity, TProperty>(this IQueryable<TEntity> query, Expression<Func<TEntity, TProperty>> navigationPropertyPath)
where TEntity : class
where TProperty : ModelBase
{
return query.Include(navigationPropertyPath).Where(/*Use the navigationPropertyPath to filter by IsDeleted*/);
}
有什么方法可以将“navigationPropertyPath”转换为另一个要在 .Where() 子句中使用的表达式。或者至少通过另一个单一的扩展方法解决方案接近这个相同的目标?
那我可以打电话给barQuery.IncludeNotDeleted(x => x.Foo)
使用以下方法生成修改后的Expression
:
private static Expression<Func<TEntity, bool>> GeneratePredicate<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> src)
where TEntity : class
where TProperty : ModelBase
{
var isDeletedPropExpr = src.Body.MakeMemberAccess(typeof(ModelBase).GetMember(nameof(ModelBase.IsDeleted)).First());
var newBody = Expression.Equal(isDeletedPropExpr, Expression.Constant(false));
return Expression.Lambda<Func<TEntity, bool>>(newBody, src.Parameters[0]);
}
然后将其集成到您的扩展方法中:
public static IQueryable<TEntity> IncludeNotDeleted<TEntity, TProperty>(this IQueryable<TEntity> query, Expression<Func<TEntity, TProperty>> navigationPropertyPath)
where TEntity : class
where TProperty : ModelBase
{
var predicate = GeneratePredicate(navigationPropertyPath);
return query.Include(navigationPropertyPath).Where(predicate);
}
上面使用了EF Core提供的MakeMemberAccess()
辅助方法
在 .NET Core 应用程序中,我有如下一对多关系。
public class ModelBase
{
public virtual long Id { get; set; }
public virtual bool IsDeleted { get; set; }
}
public class Foo : ModelBase
{
public virtual string Name { get; set; }
public virtual ICollection<Bar> Bars { get; set; }
}
public class Bar : ModelBase
{
public virtual string Name { get; set; }
public virtual long FooId { get; set; }
public virtual Foo Foo { get; set; }
}
使用 EF 3.1,我需要查询 IQueryable<Bar> barQuery
,其中相应的“Foo”在逻辑上没有被删除。
由于此应用程序不使用延迟加载,我必须执行包含以在单个数据库调用中获取任何 Foo 的 属性。所以我正在尝试实现一个扩展方法,它使用单个表达式同时调用 .Include(x => x.Foo)
和 .Where(x => !x.Foo.IsDeleted)
。
到目前为止,我实现了以下扩展方法:
public static IQueryable<TEntity> IncludeNotDeleted<TEntity, TProperty>(this IQueryable<TEntity> query, Expression<Func<TEntity, TProperty>> navigationPropertyPath)
where TEntity : class
where TProperty : ModelBase
{
return query.Include(navigationPropertyPath).Where(/*Use the navigationPropertyPath to filter by IsDeleted*/);
}
有什么方法可以将“navigationPropertyPath”转换为另一个要在 .Where() 子句中使用的表达式。或者至少通过另一个单一的扩展方法解决方案接近这个相同的目标?
那我可以打电话给barQuery.IncludeNotDeleted(x => x.Foo)
使用以下方法生成修改后的Expression
:
private static Expression<Func<TEntity, bool>> GeneratePredicate<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> src)
where TEntity : class
where TProperty : ModelBase
{
var isDeletedPropExpr = src.Body.MakeMemberAccess(typeof(ModelBase).GetMember(nameof(ModelBase.IsDeleted)).First());
var newBody = Expression.Equal(isDeletedPropExpr, Expression.Constant(false));
return Expression.Lambda<Func<TEntity, bool>>(newBody, src.Parameters[0]);
}
然后将其集成到您的扩展方法中:
public static IQueryable<TEntity> IncludeNotDeleted<TEntity, TProperty>(this IQueryable<TEntity> query, Expression<Func<TEntity, TProperty>> navigationPropertyPath)
where TEntity : class
where TProperty : ModelBase
{
var predicate = GeneratePredicate(navigationPropertyPath);
return query.Include(navigationPropertyPath).Where(predicate);
}
上面使用了EF Core提供的MakeMemberAccess()
辅助方法