从Orchard 1.5.1迁移到Orchard 1.6后,Linq'Group by'

时间:2013-01-10 13:21:58

标签: linq nhibernate orchardcms orchardcms-1.6

我有'分组'的问题。 在迁移到Orchard 1.5.1之前,我对此代码没有任何问题:

var list = (from r in GetAll()
                    group new { r.FormulaCatId, r.InputPeriodId, r.CurrencyId } by new { r.FormulaCatId, r.InputPeriodId, r.CurrencyId }
                        into grp
                        select (new CatCurPerViewModel
                        {
                            FormulaCatId = grp.Key.FormulaCatId,
                            InputPeriodId = grp.Key.InputPeriodId,
                            CurrencyId = grp.Key.CurrencyId
                        }));

但是在迁移到Orchard 1.6之后出现了这个问题:

2013-01-10 15:01:25,704 [7] Orchard.Exceptions.DefaultExceptionPolicy - An unexpected exception was caught
System.NotImplementedException: The method or operation is not implemented.
at NHibernate.Linq.CacheableExpressionNode.Resolve(ParameterExpression inputParameter, Expression   expressionToBeResolved, ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.IntermediateModel.ExpressionResolver.GetResolvedExpression(Expression unresolvedExpression, ParameterExpression parameterToBeResolved, ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.IntermediateModel.GroupByExpressionNode.<>c__DisplayClass1.<GetResolvedKeySelector>b__0(ExpressionResolver r)
at Remotion.Linq.Parsing.Structure.IntermediateModel.ResolvedExpressionCache`1.GetOrCreate(Func`2 generator)
at Remotion.Linq.Parsing.Structure.IntermediateModel.GroupByExpressionNode.CreateResultOperator(ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.IntermediateModel.ResultOperatorExpressionNodeBase.ApplyNodeSpecificSemantics(QueryModel queryModel, ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.IntermediateModel.MethodCallExpressionNodeBase.Apply(QueryModel queryModel, ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.QueryParser.ApplyAllNodes(IExpressionNode node, ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.QueryParser.GetParsedQuery(Expression expressionTreeRoot)
at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory)
at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at SAS.Core.Services.RateService.ListCatCurPer()
at SAS.Core.Controllers.RatesAdminController.Index()
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass13.<InvokeActionMethodWithFilters>b__10()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)

1 个答案:

答案 0 :(得分:2)

问题发生的原因是在Orchard 1.6中Orchard.Data.Repository的Table属性&lt; T&gt;以下列方式实施:

    public virtual IQueryable<T> Table
    {
        get { return Session.Query<T>().Cacheable(); }
    }

并且您无法使用Group By with Cacheable() - there is an open ticket in HNIbernate Jira

Orchard按顺序to leverage 2nd level Nhibernate cache执行Cacheable()调用。

如果你不使用也不打算在Orchard中使用这个二级缓存和相应的模块,你可以下载Orchard源代码,并在Orchard.Data.Repository&lt; T&gt;中更改Table属性的实现。到

    public virtual IQueryable<T> Table
    {
        get { return Session.Query<T>(); }
    }

这将解决您的问题。

或者如果您不想更改Orchard源,您可以创建自己的通用存储库类,并将其连接到DependencyContainer(默认情况下Orchard附带Autofac)。 以下是使用Autofac 2.6.3.862完成的方法:

public class MyRepository<T> : Orchard.Data.Repository<T> where T:class
{
    public MyRepository(ISessionLocator sessionLocator) : base(sessionLocator)
    {
    }

    public override System.Linq.IQueryable<T> Table
    {
        get { return Session.Query<T>(); }
    }
}

public class MyDataModule : Autofac.Module
{
    protected override void AttachToComponentRegistration(Autofac.Core.IComponentRegistry componentRegistry, Autofac.Core.IComponentRegistration registration)
    {
        base.AttachToComponentRegistration(componentRegistry, registration);

        Type limitType = registration.Activator.LimitType;
        if (!limitType.IsGenericType || limitType.GetGenericTypeDefinition() != typeof (Repository<>)) return;

        var epamRepoTye = typeof(MyRepository<>).MakeGenericType(limitType.GetGenericArguments());

        registration.Activating += (s, e) =>
                                       {
                                           var locator = e.Context.Resolve<ISessionLocator>();
                                           e.Instance = Activator.CreateInstance(epamRepoTye, new object[] {locator});
                                       };
    }
}

可能(我还没有测试过)如果可以保证包含它的程序集将晚于Orchard.Core程序集加载,可以简化MyDataModule类:

public class MyDataModule : Autofac.Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterGeneric(typeof(MyRepository<>)).As(typeof(IRepository<>)).InstancePerDependency();
    }
}