从GroupBy中选择Linq

本文关键字:Linq 选择 GroupBy | 更新日期: 2023-09-27 18:07:36

我想选择每个组到自定义类和每个项目到另一个自定义类,

我是这样做的:

_notificationsManager
    .GetUserNotifications(_repositoryNotifications, _memberShipProvider)
    .GroupBy(x => x.Category)
    .Select(g => new NotificationsGroupData {
          Name = g.Key,
          Notifications = g.Take(3).Select(s => new NotificationData  {
                                           Category = g.Key,
                                           Text = s.Text,
                                           Time = DateTime.Now.Subtract(s.Time)
                                         })
     })

这里是NotificationsGroupData:

public class NotificationsGroupData
{
    public string Name { get; set; }
    public IEnumerable<NotificationData> Notifications { get; set; }
}

和NotificationData:

public class NotificationData
{
    public virtual TimeSpan Time { get; set; }
    public virtual string Category { get; set; }
    public virtual string Text { get; set; }
}

但是当我试图在这个上面创建循环时,我得到了错误:该方法或操作未实现。

这一行:

@foreach (var group in Model.Notifications)

我该如何修复它?

Uodate: 我将代码更新为:

_notificationsManager.GetUserNotifications(_repositoryNotifications, _memberShipProvider)
                                             .GroupBy(x => x.Category)
                                             .Select(g => new
                                                 {
                                                     Name = g.Key,
                                                     Notifications =
                                                              g.OrderBy(o => o.Time)
                                                               .Take(3)
                                                               .Select(s => new
                                                                   {
                                                                       Category = g.Key,
                                                                       s.Text,
                                                                       s.Time
                                                                   })
                                                 }).AsEnumerable().Select(g => new NotificationsGroupData
                                                     {
                                                         Name = g.Name,
                                                         Notifications = g.Notifications
                                                                          .Select(s => new NotificationData
                                                                              {
                                                                                  Category = g.Name,
                                                                                  Text = s.Text,
                                                                                  Time = now - s.Time
                                                                              })
                                                     })

这里是错误:

The method or operation is not implemented.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 
Exception Details: System.NotImplementedException: The method or operation is not implemented.
Source Error: @foreach (var group in Model.Notifications)
Stack Trace: 

[NotImplementedException: The method or operation is not implemented.] NHibernate.Linq.GroupBy.NonAggregatingGroupByRewriter.FlattenSubQuery(SubQueryExpression subQueryExpression, QueryModel queryModel) +608    NHibernate.Linq.GroupBy.NonAggregatingGroupByRewriter.ReWrite(QueryModel queryModel) +598    NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root) +126    NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory) +208    NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory) +51    NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) +100    NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) +74    NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) +53  NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters) +320   NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow) +188    NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression) +164    NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery) +152    NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
+70    NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression) +59    Remotion.Linq.QueryableBase`1.GetEnumerator() +128  System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +61    ASP._Page_Views_Layout_Notifications_cshtml.Execute() in d:'Dev'Projects'ADDE'ADDE'Views'Layout'Notifications.cshtml:21    System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +197    System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +103    System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +88    System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance) +235    System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer) +107    System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
+291    System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +13    System.Web.Mvc.<>c__DisplayClass1a.<InvokeActionResultWithFilters>b__17()
+23    System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +245   System.Web.Mvc.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19()
+22    System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +176    System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20()
+75    System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +99    System.Web.Mvc.Async.WrappedAsyncResult`1.End()
+50    System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +27    System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +14    System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23    System.Web.Mvc.Async.WrappedAsyncResult`1.End() +55    System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +39 System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23    System.Web.Mvc.Async.WrappedAsyncResult`1.End() +55    System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +29    System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10    System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +25    System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23    System.Web.Mvc.Async.WrappedAsyncResult`1.End() +55    System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
+31    System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9    System.Web.Mvc.<>c__DisplayClassa.<EndProcessRequest>b__9() +22    System.Web.Mvc.<>c__DisplayClass4.<Wrap>b__3() +10    System.Web.Mvc.ServerExecuteHttpHandlerWrapper.Wrap(Func`1 func) +27   System.Web.Mvc.ServerExecuteHttpHandlerWrapper.Wrap(Action action) +64 System.Web.Mvc.ServerExecuteHttpHandlerAsyncWrapper.EndProcessRequest(IAsyncResult result) +71    System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage, VirtualPath path, VirtualPath filePath, String physPath, Exception error, String queryStringOverride) +1464
[HttpException (0x80004005): Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'.] System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage, VirtualPath path, VirtualPath filePath, String physPath, Exception error, String queryStringOverride) +3033503    System.Web.HttpServerUtility.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage) +76    System.Web.HttpServerUtility.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm) +28    System.Web.HttpServerUtilityWrapper.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm) +19    System.Web.Mvc.Html.ChildActionExtensions.ActionHelper(HtmlHelper htmlHelper, String actionName, String controllerName, RouteValueDictionary routeValues, TextWriter textWriter) +463    System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper htmlHelper, String actionName, String controllerName) +35    ASP._Page_Views_Shared__Layout_cshtml.Execute() in d:'Dev'Projects'ADDE'ADDE'Views'Shared'_Layout.cshtml:33    System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +197    System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +103    System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +88    System.Web.WebPages.<>c__DisplayClass7.<RenderPageCore>b__6(TextWriter writer) +233    System.Web.WebPages.HelperResult.WriteTo(TextWriter writer) +10    System.Web.WebPages.WebPageBase.Write(HelperResult result) +71    System.Web.WebPages.WebPageBase.RenderSurrounding(String partialViewName, Action`1 body) +64    System.Web.WebPages.WebPageBase.PopContext() +246    System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +95    System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance) +235    System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer) +107    System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
+291    System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +13    System.Web.Mvc.<>c__DisplayClass1a.<InvokeActionResultWithFilters>b__17()
+23    System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +245   System.Web.Mvc.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19()
+22    System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +176    System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20()
+75    System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +99    System.Web.Mvc.Async.WrappedAsyncResult`1.End()
+50    System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +27    System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +14    System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23    System.Web.Mvc.Async.WrappedAsyncResult`1.End() +55    System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +39 System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23    System.Web.Mvc.Async.WrappedAsyncResult`1.End() +55    System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +29    System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10    System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +25    System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23    System.Web.Mvc.Async.WrappedAsyncResult`1.End() +55    System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
+31    System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9    System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
+9629708    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

从GroupBy中选择Linq

我怀疑问题很可能出在DateTime.Now.Subtract(s.Time)部分,可能与您使用的NotificationsGroupData相结合。

我建议你改变你的查询,简单地获取所有你需要的数据,而不需要处理它太多,然后使用AsEnumerable在本地执行更复杂的工作。比如:

// Use a single common idea of "now", don't re-evaluate each time
var now = DateTime.Now;
var query = _notificationsManager
    .GetUserNotifications(_repositoryNotifications, _memberShipProvider)
    .GroupBy(x => x.Category)
    .Select(g => new {
      Name = g.Key,
      Notifications = g.Take(3)
                       .Select(s => new {
                           Text = s.Text,
                           Time = s.Time
                       })
    })
    .AsEnumerable() // Force local evaluation for final step
    .Select(g => new NotificationsGroupData {
      Name = g.Name,
      Notifications = g.Notifications
                       .Select(s => new NotificationData {
                           Category = g.Name,
                           Text = s.Text,
                           Time = now - s.Time
                       })
    });

编辑:好吧,因为这仍然会产生问题,你可以尝试在分组后执行所有操作:

var now = DateTime.Now;
var query = _notificationsManager
    .GetUserNotifications(_repositoryNotifications, _memberShipProvider)
    .GroupBy(x => x.Category)
    .AsEnumerable() // Force local evaluation for final step
    .Select(g => new NotificationsGroupData {
      Name = g.Key,
      Notifications = g.Take(3)
                       .Select(s => new NotificationData {
                           Category = g.Key,
                           Text = s.Text,
                           Time = now - s.Time
                       })
    });

请注意,这远非理想-它将从数据库中提取所有属性,而不仅仅是您想要的那些。(而且不仅仅是前三个——尽管"第一"也取决于顺序,但我们看到的任何地方都没有指定顺序。)这可能是其中一种情况,你需要回到SQL,但它确实听起来像NHibernate可以为你做更多的…

NHibernate不能将你的查询转换为sql。最快的解决方案是让你的选择语句在内存集合上而不是传递给NHibernate。试试这个:

_notificationsManager
    .GetUserNotifications(_repositoryNotifications, _memberShipProvider)
    .GroupBy(x => x.Category)
    .ToList()
    .Select(g => new NotificationsGroupData {
          Name = g.Key,
          Notifications = g.Take(3).Select(s => new NotificationData  {
                                           Category = g.Key,
                                           Text = s.Text,
                                           Time = DateTime.Now.Subtract(s.Time)
                                         })
     })

另一种选择是在HQL'SQL上编写查询并将其传递给NHibernate,这样您就可以从数据库中提取必要数量的数据并将其映射到您的自定义实体。