我的 Linq where 子句如何转换为 Sql 时遇到问题。
我正在使用EnumToStringConverter
将我的实体的属性映射enum
到文本数据库列中。当从 DbContext 查询我的实体时,这一切都很好。
然后我开始使用 LinqKit 和 Expressions 来获得可重用的过滤器。我创建了一个表达式,它接受我的实体并作为对实体其他属性的一些计算的结果给出我的枚举。我会尝试用代码来解释自己,因为文字让我失望。我会写一个例子,所以我不必发布完整的代码,但逻辑是一样的。您可以在此处找到带有项目的 GitHub 存储库来复制该问题: https //github.com/pinoy4/efcore-enum-to-string-test
模型类:
public class MyEntity
{
public Guid Id { get; set; }
public MyEnum Status { get; set; }
public DateTime DueAtDate { get; set; }
}
public MyEnum
{
New = 0,
InProgress = 1,
Overdue = 2
}
Run Code Online (Sandbox Code Playgroud)
FluentAPI 配置
public class MyEntityConfiguration : IEntityTypeConfiguration<MyEntity>
{
public void Configure(EntityTypeBuilder<MyEntity> builder)
{
// irrelevant parts of configuration …
Run Code Online (Sandbox Code Playgroud) 我需要通过将文档列表传递给我正在努力使用循环动态构建的自定义过滤器来过滤文档列表foreach
:
var mainPredicate = PredicateBuilder.True<Document>();
// mainPredicate is combined to other filters successfully here ...
var innerPredicate = PredicateBuilder.False<Document>();
foreach (var period in periods)
{
var p = period;
Expression<Func<Document, bool>> inPeriod =
d => d.Date >= p.DateFrom && d.Date <= p.DateTo;
innerPredicate = innerPredicate.Or(d => inPeriod.Invoke(d));
}
mainPredicate = mainPredicate.And(innerPredicate);
Run Code Online (Sandbox Code Playgroud)
最后一行:
documents = this.ObjectSet.AsExpandable().Where(mainPredicate).ToList();
Run Code Online (Sandbox Code Playgroud)
引发此异常:
参数"d"未绑定在指定的LINQ to Entities查询表达式中.
任何人都知道为什么我得到这个例外?我不明白我传递给InPeriod方法的'd'参数丢失了.我不知道为什么缺少这个工作.我的代码与许多其他完美运行的示例相同.任何关于调用表达式的理论理论信息及其在幕后的工作方式都是值得欢迎的.
c# linq-to-entities expression-trees linq-expressions linqkit
我正在尝试动态构造一个类似于下面的表达式,我可以使用相同的比较函数,但是可以传入被比较的值,因为值是从属性'higher-up'传递的查询.
var people = People
.Where(p => p.Cars
.Any(c => c.Colour == p.FavouriteColour));
Run Code Online (Sandbox Code Playgroud)
我相信我已正确构造了查询,但是ExpressionExpander.VisitMethodCall(..)
当我尝试使用它时,该方法会抛出以下异常:
"无法将'System.Linq.Expressions.InstanceMethodCallExpressionN'类型的对象强制转换为'System.Linq.Expressions.LambdaExpression'"
在真实世界的代码中,使用实体框架和实际IQueryable<T>
,我经常得到:
"无法将类型为'System.Linq.Expressions.MethodCallExpressionN'的对象转换为'System.Linq.Expressions.LambdaExpression'".
我构建了一个LinqPad友好的问题示例,就像我能做到的那样简单.
void Main()
{
var tuples = new List<Tuple<String, int>>() {
new Tuple<String, int>("Hello", 4),
new Tuple<String, int>("World", 2),
new Tuple<String, int>("Cheese", 20)
};
var queryableTuples = tuples.AsQueryable();
// For this example, I want to check which of these strings are longer than their accompanying number.
// The expression I want to build needs to use one of the …
Run Code Online (Sandbox Code Playgroud) Unable to cast object of type 'System.Linq.Expressions.FieldExpression' to type 'System.Linq.Expressions.LambdaExpression'
运行以下代码时出现错误。
这段代码的目的是让我过滤包含某些字符串的记录(实体框架代码优先/Linq to SQL)。
注意:我正在使用第三方库 LinqKit:http : //www.albahari.com/nutshell/predicatebuilder.aspx
FilterHelper<Country> helper = new FilterHelper<Country>();
helper.AddContains(searchAlpha2, c => c.Alpha2);
helper.AddContains(searchAlpha3, c => c.Alpha3);
helper.AddContains(searchName, c => c.Name);
IQueryable<Country> countries = db.Countries.AsExpandable().Where(helper.Predicate);
Run Code Online (Sandbox Code Playgroud)
...
public class FilterHelper<T>
{
public delegate string GetColumn<T>(T item);
private Expression<Func<T,bool>> predicate;
public FilterHelper()
{
this.predicate = PredicateBuilder.True<T>();
}
public void AddContains(string searchText, GetColumn<T> getColumn)
{
if (!string.IsNullOrWhiteSpace(searchText))
predicate = predicate.And(c => getColumn(c) != null ? getColumn(c).Contains(searchText) : false); …
Run Code Online (Sandbox Code Playgroud) var predicate = PredicateBuilder.True<o_order>();
Run Code Online (Sandbox Code Playgroud)
这是我的谓词表达式,在某些条件下,我会用它附加表达式.
同样
if (!string.IsNullOrEmpty(param.sSearch))
predicate = predicate.And(s => s.OrderID.ToString().Contains(param.sSearch));
Run Code Online (Sandbox Code Playgroud)
现在我的问题是,如果这个表达式没有通过这个条件,那么会有任何表达式吗?我怎么知道它是否没有返回表达式.
我只想做 -
if(predicate==null)
要么 if(predicate contains no expression)
我正在尝试使用 Linq/LinqKit 构建嵌套查询。从理论上讲,这似乎很容易。但我坚持实践部分。
在我的数据库中,我有一个表,该表具有对其父级的自引用。在我的 linq-query 中,我现在想要选择给定元素的所有父元素(以及该元素的父元素,依此类推)。
在我的代码中,我的部分类中有以下表达式MyTable
:
public static Expression<Func<MyTable, IEnumerable<MyTable>>> Parents => (entity) => entity.ParentId != null ? new[]{entity.ParentEntity}.Union(Parents.Invoke(entity.ParentEntity) : new MyEntity[]{};
Run Code Online (Sandbox Code Playgroud)
它应该选择给定实体的父级以及ParentId
设置时的那些父级。
查询本身(简化):
dbContext
.MyTable
.AsExpandable()
.Where(x => x.Id == myId)
.Select(x => new
{
Parents = MyTable.Parents.Invoke(x, dbContext)
});
Run Code Online (Sandbox Code Playgroud)
运行此代码最终会出现 in StackOverflowException
,因为未达到停止条件,因此Parents
-call 会无限嵌套,直到堆栈已满。
有什么想法可以做到这一点还是不可能?或者是否有其他方法可以在一个查询中使用Linq
/获取嵌套数据LinqKit
?
我已经尝试将上下文传递给表达式以创建子查询(也不起作用):
public static Expression<Func<MyTable, MyContext, IEnumerable<MyTable>>> Parents => (entity, dbContext) => entity.ParentId != null ? new[]{entity.ParentEntity}.Union(Parents.Invoke(dbContext.MyTable.FirstOrDefault(x => x.Id == entity.ParentId), dbContext) : …
Run Code Online (Sandbox Code Playgroud) 我在下面的代码中使用Generic Filter,传递了任何搜索文本,但contains方法是区分大小写的,我怎样才能写入忽略大小写.
public static class QueryExtensions
{
public static IQueryable<T> Filter<T>(this IQueryable<T> query, string search)
{
var properties = typeof(T).GetProperties().Where(p =>
/*p.GetCustomAttributes(typeof(System.Data.Objects.DataClasses.EdmScalarPropertyAttribute),true).Any() && */
p.PropertyType == typeof(String));
var predicate = PredicateBuilder.False<T>();
foreach (var property in properties )
{
predicate = predicate.Or(CreateLike<T>(property,search));
}
return query.AsExpandable().Where(predicate);
}
private static Expression<Func<T,bool>> CreateLike<T>( PropertyInfo prop, string value)
{
var parameter = Expression.Parameter(typeof(T), "f");
var propertyAccess = Expression.MakeMemberAccess(parameter, prop);
var like = Expression.Call(propertyAccess, "Contains", null, Expression.Constant(value,typeof(string)));
return Expression.Lambda<Func<T, bool>>(like, parameter);
}
}
Run Code Online (Sandbox Code Playgroud) 在那里,我只看到最新的LINQKit版本依赖于EF 6.0.2,我需要在EF 5.0上安装,是否有一个较旧的LINQKit版本兼容EF 5.0?或其他东西来替换它(.Expand()功能)?
假设我已经定义了以下变量:
IQueryable<MyClass> myQueryable;
Dictionary<string, Expression<Func<MyClass, bool>>> extraFields;
// the dictionary is keyed by a field name
Run Code Online (Sandbox Code Playgroud)
现在,我想将一些动态字段添加到IQueryable中,以便它返回一个IQueryable<ExtendedMyClass>
,其中ExtendedMyClass
定义为:
class ExtendedMyClass
{
public MyClass MyObject {get; set;}
public IEnumerable<StringAndBool> ExtraFieldValues {get; set;}
}
class StringAndBool
{
public string FieldName {get; set;}
public bool IsTrue {get; set;}
}
Run Code Online (Sandbox Code Playgroud)
换句话说,对于每个值extraFields
,我希望有一个值来ExtendedMyClass.ExtraFieldValues
表示该表达式是否为该行的计算结果为True.
我有一种感觉,这应该在动态的Linq和LinqKit中可行,尽管我以前从未认真对待过.我也对其他建议持开放态度,特别是如果这可以通过良好的"强力型Linq"来完成.
我正在使用Linq to Entities,因此查询需要转换为SQL.
我正在尝试LinqKit
AsExpandable
在我的EfCore2.0
项目中使用,但遇到了Includes
不起作用的问题。
在尝试调试时,我LinqKit
从 github下载了源代码,并Nuget
用项目引用替换了我项目中的引用。
在调试LinqKit
项目时,我注意到我的调用Include
没有达到我在 上设置的断点ExpandableQueryOfClass<T>.Include
。
我做了一些进一步的测试并注意到如果我第一次转换到断点会被击中ExpandableQueryOfClass
(这是一个LinqKit
我公开的内部类,所以如果我引用Nuget
包,我就不能做转换)。
这是一个错误LinqKit
还是我做错了什么?
这是我的测试代码。
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Internal.DAL.Db;
using Internal.Models.Customer;
using LinqKit; // Referencing LinqKit.Microsoft.EntityFrameworkCore
using Xunit;
namespace Internal.EntityFramework.Tests
{
public class UnitTest1
{
private DbContextOptionsBuilder<DataContext> _ctxBuilder =>
new DbContextOptionsBuilder<DataContext>().UseSqlServer(Connection.String);
[Fact]
public async Task SuccessTest()
{
using (var ctx = new DataContext(_ctxBuilder.Options))
{
var query …
Run Code Online (Sandbox Code Playgroud) linqkit ×10
c# ×8
linq ×5
expression ×2
.net ×1
.net-core ×1
asp.net-mvc ×1
dynamic-linq ×1
ef-core-2.0 ×1
ef-core-2.2 ×1
lambda ×1
linq-to-sql ×1
nested ×1