我正在尝试生成以下LINQ查询:
//Query the database for all AdAccountAlerts that haven't had notifications sent out
//Then get the entity (AdAccount) the alert pertains to,and find all accounts that
//are subscribing to alerts on that entity.
var x = dataContext.Alerts.Where(a => a.NotificationsSent == null)
  .OfType<AdAccountAlert>()
  .ToList()
  .GroupJoin(dataContext.AlertSubscriptions,a => new Tuple<int,string>(a.AdAccountId,typeof(AdAccount).Name),s => new Tuple<int,string>(s.EntityId,s.EntityType),(Alert,Subscribers) => new Tuple<AdAccountAlert,IEnumerable<AlertSubscription>> (Alert,Subscribers))
  .Where(s => s.Item2.Any())
  .ToDictionary(kvp => (Alert)kvp.Item1,kvp => kvp.Item2.Select(s => s.Username));

使用表达式树(当我需要使用反射和运行时类型时,这似乎是我能做到这一点的唯一方法).请注意,在实际代码中(见下文),AdAccountAlert实际上是通过反射和for循环动态的.

我的问题:我可以生成.Where()子句的所有内容.由于类型不兼容,whereExpression方法调用会爆炸.通常我知道要放在那里,但Any()方法调用让我感到困惑.我尝试了所有我能想到的类型而且没有运气.任何有关.Where()和.ToDictionary()的帮助都将受到赞赏.

这是我到目前为止所拥有的:

var alertTypes = AppDomain.CurrentDomain.GetAssemblies()
  .Single(a => a.FullName.StartsWith("Alerts.Entities"))
  .GetTypes()
  .Where(t => typeof(Alert).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface);

var alertSubscribers = new Dictionary<Alert,IEnumerable<string>>();

//Using tuples for joins to keep everything strongly-typed
var subscribableType = typeof(Tuple<int,string>);
var doubleTuple = Type.GetType("System.Tuple`2,mscorlib",true);

foreach (var alertType in alertTypes)
{
  Type foreignKeyType = GetForeignKeyType(alertType);
  if (foreignKeyType == null)
    continue;

  IQueryable<Alert> unnotifieDalerts = dataContext.Alerts.Where(a => a.NotificationsSent == null);

  //Generates: .OfType<alertType>()
  MethodCallExpression alertsOfType = Expression.Call(typeof(Enumerable).getmethod("OfType").MakeGenericmethod(alertType),unnotifieDalerts.Expression);

  //Generates: .ToList(),which is required for joins on Tuples
  MethodCallExpression unnotifieDalertsList = Expression.Call(typeof(Enumerable).getmethod("ToList").MakeGenericmethod(alertType),alertsOfType);

  //Generates: a => new { a.{EntityId},EntityType = typeof(AdAccount).Name }
  ParameterExpression alertParameter = Expression.Parameter(alertType,"a");
  MemberExpression adAccountId = Expression.Property(alertParameter,alertType.GetProperty(alertType.GetForeignKeyId()));
  NewExpression outerJoinObject = Expression.New(subscribableType.GetConstructor(new Type[] { typeof(int),typeof(string)}),adAccountId,Expression.Constant(foreignKeyType.Name));
  LambdaExpression outerSelector = Expression.Lambda(outerJoinObject,alertParameter);

  //Generates: s => new { s.EntityId,s.EntityType }
  Type alertSubscriptionType = typeof(AlertSubscription);
  ParameterExpression subscriptionParameter = Expression.Parameter(alertSubscriptionType,"s");
  MemberExpression entityId = Expression.Property(subscriptionParameter,alertSubscriptionType.GetProperty("EntityId"));
  MemberExpression entityType = Expression.Property(subscriptionParameter,alertSubscriptionType.GetProperty("EntityType"));
  NewExpression innerJoinObject = Expression.New(subscribableType.GetConstructor(new Type[] { typeof(int),typeof(string) }),entityId,entityType);
  LambdaExpression innerSelector = Expression.Lambda(innerJoinObject,subscriptionParameter);

  //Generates: (Alert,Subscribers) => new Tuple<Alert,IEnumerable<AlertSubscription>>(Alert,Subscribers)
  var joinResultType = doubleTuple.MakeGenericType(new Type[] { alertType,typeof(IEnumerable<AlertSubscription>) });
  ParameterExpression alertTupleParameter = Expression.Parameter(alertType,"Alert");
  ParameterExpression subscribersTupleParameter = Expression.Parameter(typeof(IEnumerable<AlertSubscription>),"Subscribers");
  NewExpression joinResultObject = Expression.New(
    joinResultType.GetConstructor(new Type[] { alertType,typeof(IEnumerable<AlertSubscription>) }),alertTupleParameter,subscribersTupleParameter);

  LambdaExpression resultsSelector = Expression.Lambda(joinResultObject,subscribersTupleParameter);

  //Generates:
  //  .GroupJoin(dataContext.AlertSubscriptions,//    a => new { a.AdAccountId,typeof(AdAccount).Name },//    s => new { s.EntityId,s.EntityType },//    (Alert,Subscribers))
  IQueryable<AlertSubscription> alertSubscriptions = dataContext.AlertSubscriptions.AsQueryable();
  MethodCallExpression joinExpression = Expression.Call(typeof(Enumerable),"GroupJoin",new Type[]
    {
      alertType,alertSubscriptions.ElementType,outerSelector.Body.Type,resultsSelector.ReturnType
    },unnotifieDalertsList,alertSubscriptions.Expression,outerSelector,innerSelector,resultsSelector);

  //Generates: .Where(s => s.Item2.Any())
  ParameterExpression subscribersParameter = Expression.Parameter(resultsSelector.ReturnType,"s");
  MemberExpression tupleSubscribers = Expression.Property(subscribersParameter,resultsSelector.ReturnType.GetProperty("Item2"));
  MethodCallExpression hasSubscribers = Expression.Call(typeof(Enumerable),"Any",new Type[] { alertSubscriptions.ElementType },tupleSubscribers);
  LambdaExpression whereLambda = Expression.Lambda(hasSubscribers,subscriptionParameter);
  MethodCallExpression whereExpression = Expression.Call(typeof(Enumerable),"Where",new Type[] { joinResultType },joinExpression,whereLambda);

解决方法

请注意:Tolist()之后的所有内容都不适用于IQueryable< T>但是在IEnumerable< T>上.因此,不需要创建表达式树.它当然不是EF或类似的解释.

如果您查看编译器为原始查询生成的代码,您会看到它仅在第一次调用ToList之前生成表达式树.

例:

以下代码:

var query = new List<int>().AsQueryable();
query.Where(x => x > 0).ToList().FirstOrDefault(x => x > 10);

由编译器翻译为:

IQueryable<int> query = new List<int>().AsQueryable<int>();
IQueryable<int> arg_4D_0 = query;
ParameterExpression parameterExpression = Expression.Parameter(typeof(int),"x");
arg_4D_0.Where(Expression.Lambda<Func<int,bool>>(Expression.GreaterThan(parameterExpression,Expression.Constant(0,typeof(int))),new ParameterExpression[]
{
    parameterExpression
})).ToList<int>().FirstOrDefault((int x) => x > 10);

请注意它如何为ToList之前的所有内容生成表达式.包含它之后的所有内容都只是对扩展方法的正常调用.

如果你没有在你的代码中模仿这个,你实际上会将一个Enumerable.ToList调用发送到LINQ提供程序 – 然后它会尝试转换为sql并失败.

c# – LINQ Expression Tree Any()里面的Where()的更多相关文章

  1. InputTransparent = true在Xamarin Forms Android中不起作用

    解决方法InputTransparent不适用于Android.我为StackLayout创建了简单的渲染:在PCL项目中:在Android项目中:我在我的xaml中使用它:这是儿童控制的工作.

  2. 萌新HTML5 入门指南(二)

    这篇文章主要介绍了萌新如何入门html5,帮助大家更好的理解和制作网页,感兴趣的朋友可以了解下

  3. JavaScript中的typeof操作符用法实例

    在Web前端开发中,我们经常需要判断变量的数据类型。鉴于ECMAScript是松散类型的,因此需要有一种手段来检测给定变量的数据类型——typeof就是负责提供这方便信息的操作符。

  4. 浅谈typescript中keyof与typeof操作符用法

    本文主要介绍了typescript中keyof与typeof操作符用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  5. 关于javascript中的typeof和instanceof介绍

    typeof用来检测给定变量的数据类型instanceof用来检测对象的类型

  6. 判断js中各种数据的类型方法之typeof与0bject.prototype.toString讲解

    提醒大家,Object.prototype.toString().call(param)返回的[object class]中class首字母是大写,像JSON这种甚至都是大写,所以,大家判断的时候可以都转换成小写,以防出错

  7. 菜鸟也能搞懂js中typeof与instanceof区别

    instanceof和typeof是两个运算符,在程序设计中用到,常用来判断一个变量是否为空,或者是什么类型的,本文就来介绍一下typeof与instanceof区别,感兴趣的可以了解一下

  8. 在JavaScript中typeof的用途介绍

    本篇文章,小编为大家介绍,在JavaScript中typeof的用途介绍。不过在阅读本文的前提是,你现在应该已经知道原始值和对象值的区别了

  9. TypeScript Typeof运算符的5个实用技巧详解

    这篇文章主要为大家介绍了TypeScript Typeof运算符的5个实用技巧详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. 浅谈js基本数据类型和typeof

    下面小编就为大家带来一篇浅谈js基本数据类型和typeof。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

随机推荐

  1. c# – (wpf)Application.Current.Resources vs FindResource

    所以,我正在使用C#中的WPF创建一个GUI.它看起来像这样:它现在还没有完成.这两行是我尝试制作一种数据表,它们在XAML中是硬编码的.现在,我正在C#中实现添加新的水果按钮功能.我在XAML中有以下样式来控制行的背景图像应该是什么样子:因此,在代码中,我为每列col0,col1和col2创建一个图像,如果我使用以下代码,它添加了一个如下所示的新行:如你所见,它不太正确……为什么一个似乎忽略了一些属性而另一个没有?

  2. c# – 绑定DataGridTemplateColumn

    似乎我已经打了个墙,试图在DataGrid上使用DataTemplates.我想要做的是使用一个模板来显示每个单元格的两行文本.但是似乎无法以任何方式绑定列.以下代码希望显示我想做的事情.注意每个列的绑定:模板列没有这样的东西,因此,这个xaml不可能工作.我注定要将整个DataTemplate复制到每个列,只是对每个副本都有不同的约束?解决方法我不完全确定你想要做什么,但如果您需要获取整行的DataContext,可以使用RelativeSource绑定来移动视觉树.像这样:

  3. c# – 学习设计模式的资源

    最近我来到了这个设计模式的概念,并对此感到非常热情.你能建议一些帮助我深入设计模式的资源吗?

  4. c# – 是否有支持嵌入HTML页面的跨操作系统GUI框架?

    我想开发一个桌面应用程序来使用跨系统,是否有一个GUI框架,允许我为所有3个平台编写一次代码,并具有完全可脚本化的嵌入式Web组件?我需要它有一个API来在应用程序和网页之间进行交流.我知道C#,JavaScript和一些python.解决方法Qt有这样的事情QWebView.

  5. c# – 通过字符串在对象图中查找属性

    我试图使用任意字符串访问嵌套类结构的各个部分.给出以下(设计的)类:我想要从Person对象的一个实例的“PersonsAddress.HousePhone.Number”获取对象.目前我正在使用反思来做一些简单的递归查找,但是我希望有一些忍者有更好的想法.作为参考,这里是我开发的(crappy)方法:解决方法您可以简单地使用标准的.NETDataBinder.EvalMethod,像这样:

  6. c# – 文件下载后更新页面

    FamilyID=0a391abd-25c1-4fc0-919f-b21f31ab88b7&displaylang=en&pf=true它呈现该页面,然后使用以下元刷新标签来实际向用户提供要下载的文件:你可能需要在你的应用程序中做类似的事情.但是,如果您真的有兴趣在文件完全下载后执行某些操作,那么您的运气不佳,因为没有任何事件可以与浏览器进行通信.执行此操作的唯一方法是上传附件时使用的AJAXupload.

  7. c# – 如何在每个机器应用程序中实现单个实例?

    我必须限制我的.net4WPF应用程序,以便每台机器只能运行一次.请注意,我说每个机器,而不是每个会话.我使用一个简单的互斥体实现单实例应用程序,直到现在,但不幸的是,这样一个互斥是每个会话.有没有办法创建机器互连,还是有其他解决方案来实现每个机器应用程序的单个实例?

  8. c# – WCF和多个主机头

    我的雇主网站有多个主机名,都是同一个服务器,我们只是显示不同的皮肤来进行品牌宣传.不幸的是,在这种情况下,WCF似乎不能很好地工作.我试过overridingthedefaulthostwithacustomhostfactory.这不是一个可以接受的解决方案,因为它需要从所有主机工作,而不仅仅是1.我也看过thisblogpost,但是我无法让它工作,或者不是为了解决我的问题.我得到的错误是“这

  9. c# – ASP.NET MVC模型绑定与表单元素名称中的虚线

    我一直在搜索互联网,试图找到一种方式来容纳我的表单元素的破折号到ASP.NET的控制器在MVC2,3或甚至4中的默认模型绑定行为.作为一名前端开发人员,我更喜欢在我的CSS中使用camelCase或下划线进行破折号.在我的标记中,我想要做的是这样的:在控制器中,我会传入一个C#对象,看起来像这样:有没有办法通过一些正则表达式或其他行为来扩展Controller类来适应这种情况?我讨厌这样的事实,我必须这样做:甚至这个:思考?

  10. c# – 用户界面设计工具

    我正在寻找一个用户界面设计工具来显示文档中可能的GUI.我不能生成代码.我知道MicrosoftVisio提供了一个功能.但有什么办法吗?您使用哪种软件可视化GUI?

返回
顶部