LINQSelectDynamicColumnsandValues由于各种原因,我需要能够让用户根据他们选择的列和值从数据库中选择项目.例如,如果我有一张表:特产|等级------+----------------+-----约翰|篮子编织|12莎莉|篮子编织|6史密斯|击剑|12用户可以请求1个、2个或更多列,并且他们请求的列可以不同。例如,用户可以请求其中专业==篮子编织和等级==12。我目前所做的是收集用户的请求并创建一个条目等级==12的列表。我目前所做的是收集用户的请求并创建一个列表ofKeyValuePairRank==12.我目前所做的是收集用户的请求并创建一个列表,其中Key是列名,Value是预期值列表:classUserSearch{privateListSearch(){using(vardb=newMyDbContext()){varentries=awaitdb.MyTable.ToListAsync();varmatches=entries.Where(e=>criteria.Select(c=>e.GetType()?.GetProperty(c.键)?.GetValue(e)?.ToString()==c.Value).All(c=>c==true));返回matches.ToList();看来我的问题出在这段代码上:e.GetType()?.GetProperty(c.Key)?.GetValue(e)?.ToString()我不熟悉表达式树,所以答案可能在于在其中我也可以尝试动态LINQ。由于您的列和过滤器是动态的,因此动态LINQ库可以帮助您NuGet:https://www.nuget.org/packages/System.Linq.Dynamic/Doc:http://dynamiclinq.azurewebsites.net/使用System.Linq.Dynamic;//导入动态LINQ库//标准方式,需要编译时知识//数据模型varresult=myQuery.Where(x=>x.Field1=="SomeValue").Select(x=>新的{x.Field1,x.Field2});//DynamicLINQ方式,它让你做同样的事情//而无需事先了解数据模型varresult=myQuery.Where("Field1="SomeValue"").Select("new(Field1,Field2)");另一种解决方案是使用EvalExpression.NET,它允许您在运行时动态评估C#代码。使用(varctx=newTestContext()){varquery=ctx.Entity_Basics;varlist=Eval.Execute(@"q.Where(x=>x.ColumnIntnew{x.ID,x.ColumnInt}).ToList();",new{q=query});免责声明:我是EvalExpression.NET项目的所有者编辑:回答评论请注意,参数值类型必须与属性类型兼容。例如,如果“Rank”属性是一个INT,则只有与INT兼容的类型才有效(不是字符串)。显然,您需要重构此方法,使其更适合您的应用程序。但如您所见,您可以轻松地在EntityFramework中使用异步方法。如果你还自定义了select(返回类型),你可能需要使用反射来获取异步结果,或者使用ExecuteAsync代替ToList()。publicasyncTask>DynamicWhereAsync(CancellationTokencancellationToken=default(CancellationToken)){//从实体框架注册异步扩展方法(这应该在global.asax或STAThread方法中完成//默认情况下仅存在Enumerable&&Queryable扩展方法EvalManager。DefaultContext.RegisterExtensionMethod(typeof(QueryableExtensions));//获取你的条件vartuples=newList>();tuples.Add(newTuple("Specialty","BasketWeaving"));tuples.Add(newTuple("Rank","12"));//构建你的where子句varwhere=string.Join("&&",tuples.Select(tuple=>string.Concat("x.",tuple.Item1,">p",tuple.Item1)));//建立你的参数varparameters=newDictionary();tuples.ForEach(x=>parameters.Add("p"+x.Item1,x.Item2));using(varctx=newTestContext()){varquery=ctx.Entity_Basics;//添加当前查询&&cancellationToken作为参数parameters.Add("q",query);parameters.Add("token",cancellationToken);//获取任务vartask=(Task>)Eval.Execute("q.Where(x=>"+where+").ToListAsync(token)",parameters);//AWAITtaskvarresult=awaittask.ConfigureAwait(false);returnresult;}}尝试将此作为动态where子句的一般模式://examplelists,填充的解决方案将遵循ListNames=newList(){"Adam","Joe","Bob"};//这两个为了演示目的巧妙地留空ListSpecialties=newList(){};ListRanks=newList(){};using(vardbContext=newMyDbContext()){varlist=dbContext.MyTable.Where(x=>(!Names.Any()||Names.Contains(x.Name))&&(!Specialties.Any()||Specialties.Contains(x.Specialty))&&(!Ranks.Any()||Ranks.Contains(x.Rank))).ToList();}对基础数据做出一些假设,下面是上面显示的LINQ可能生成的SQL:DECLARE@p0NVarChar(1000)='Adam'DECLARE@p1NVarChar(1000)='Joe'DECLARE@p2NVarChar(1000)='Bob'SELECT[t0].[Name].[t0].[Specialty].[t0]。[Rank]FROM[MyTable]AS[t0]WHERE[t0].[Name]IN(@p0,@p1,@p2)在UserSearch类中填充这些列表:foreach(varkvpincriteria){switch(kvp.Key){case"Name":Names.Add(kvp.Value);休息;案例“专业”:Specialties.Add(kvp.Value);休息;case"Rank":Ranks.Add(kvp.Value);休息;更改,那么您可能希望返回到通过SqlCommand类使用原始SQL。这样,您可以轻松生成动态选择和where子句。您甚至可以查询表中的列列表以动态确定哪些选项可用于选择/过滤。不知道你在这之后是什么。但这应该给你一个想法。varquery=db.Mytable.Where(x=>x.Specialty==criteria[0].Value&&c=>c.Rank==criteria[1].Value).ToString();我什至不确定为什么你Even必须使用List。因为List需要迭代。您可以使用Keyfirst、Firstcondition和Value作为lastcondition来避免KeyValuePair列表。美好的。让我给我两分钱。如果你想使用动态LINQ,表达式树应该是你的选择。您可以根据需要生成动态LINQ语句。像下面这样的东西应该会产生魔力。//在泛型类中。publicstaticIQueryableGetWhere(stringcriteria1,stringcriteria2,stringcriteria3,stringcriteria4){vart=MyExpressions.DynamicWhereExp(criteria1,criteria2,criteria3,criteria4);返回db.Set().Where(t);现在在另一个泛型类中,您可以将表达式定义为。publicstaticExpression>DynamicWhereExp(stringcriteria1,stringcriteria2,stringcriteria3,stringcriteria4){ParameterExpressionParam=Expression.Parameter(typeof(T));表达式exp1=WhereExp1(criteria1,criteria2,Param);表达式exp2=WhereExp1(criteria3,criteria4,Param);varbody=Expression.And(exp1,exp2);返回Expression.Lambda>(body,Param);}privatestaticExpressionWhereExp1(stringfield,stringtype,ParameterExpressionparam){ExpressionaLeft=Expression.属性(参数,typeof(T)。GetProperty(字段));表达式aRight=Expression.Constant(type);表达式typeCheck=Expression.Equal(aLeft,aRight);返回类型检查;现在您可以在任何地方调用该方法。//从用户获取搜索条件varobj=newYourClass();varresult=obj.GetWhere(criteria1,criteria2,criteria3,criteria4);这将为您提供一个带有两个条件的强大动态表达式,在它们之间使用AND运算符,以便在LINQ的where扩展方法中使用。现在你可以根据自己的策略按需传递参数了。例如,在paramsstring[]或键值对列表中……没关系。如您所见,这里没有固定的东西。它是完全动态的,比反射更快,您可以根据需要制作尽可能多的表达式和标准...继续@Jakotheshadows的回答,但是当没有什么可检查的时候就不会需要所有额外的检查EF输出,这更接近我们在这里所做的://示例列表,填充解决方案将遵循varNames=newList{"Adam","Joe","Bob"};//这两个为了演示目的故意留空varspecialties=newList();varranks=new列表();使用(vardbContext=newMyDbContext()){varlist=dbContext.MyTable.FilterByNames(名称).FilterBySpecialties(专业).FilterByRanks(排名).Select(...).ToList();}table[Table(...)]publicclassMyTable:IMyTable{//...}按扩展名过滤{if(query==null){thrownewArgumentNullException(nameof(query));}if(!names.Any()||names.All(string.IsNullOrWhiteSpace)){返回查询;//未修改}//修改返回query.Where(x=>names.Contains(x.Name));}//按数组/过滤器复制...}此外,在EF查询中使用Contains(...)或Any(...)会产生严重的性能问题使用PredicateBuilders方法要快得多。下面是一个带有ID数组的示例(这需要LinqKitnuget包):(x=>x>0&&x!=int.MaxValue)){返回查询;}returnquery.AsExpandable().Where(BuildIDsPredicate(ids));}privatestaticExpression>BuildIDsPredicate(IEnumerableids)其中TEntity:class,IBase{returnids.Aggregate(PredicateBuilder.New(false),(c,id)=>c.Or(p=>p.ID==id));}Thisoutputthe"IN"syntaxforveryfastqueries:以上是C#学习教程的全部内容:LINQ选择动态列和值共享。如果对大家有用,需要进一步了解C#学习教程,希望大家多加关注—WHEREIDIN[1,2,3,4,5]本文收集自网络,不代表一个位置。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
