通过单独的`List <string>`变量对Order列进行排序

时间:2016-08-31 20:03:35

标签: c# entity-framework linq

我需要通过另一个列表中的元素索引对实体框架查询的结果进行排序。

我尝试了其他地方的建议,比如

.ThenBy(m=>list.IndexOf(m.Term))

但我收到了HTTP 500错误,因此我想知道我是否遗漏了某些内容。调试时,我得到了这个内部异常。

  

LINQ to Entities无法识别方法&#39; Int32   的IndexOf(System.String)&#39;方法,这个方法无法翻译   进入商店表达。

特别是,我正在考虑这种情况。

private IEnumerable<MiaLog1A> PopulateQuery(string selectedCampus)
{
    var list = new List<string> {"No Longer Alphabetical","Fall","Mid","Spring"};
    return _db.MiaLog1A.Where(m => m.Campus == selectedCampus)
            .OrderBy(m => m.StudentName)
            .ThenBy(m=>m.Term)  
                    /* I would like to sort "Term" by the 
                     * order of "list".
                     */
        .AsEnumerable();
}

我是否有办法以这种方式排序,还是仅限于通过字典排序或创建连接?

2 个答案:

答案 0 :(得分:3)

这应该可以解决问题:

private IEnumerable<MiaLog1A> PopulateQuery(string selectedCampus)
{
    var list = new List<string> {"Fall","Mid","Spring"};
    return _db.MiaLog1A.Where(m => m.Campus == selectedCampus)
        .AsEnumerable()
        .OrderBy(m => m.StudentName)
        .ThenBy(m=> list.IndexOf(m.Term));
}

答案 1 :(得分:1)

这是一种疯狂的做法,但它并没有回归到IEnumerable

var db = new BloggingContext();

var list = (new List<string> { "FR", "EN" }).
    Select((s,i)=> $"select '{s}' as {nameof(OrderIndex.Name)},{i} as {nameof(OrderIndex.Id)}");

var order = db.Set<OrderIndex>().FromSql(String.Join(" union ",list));

var orderedItems = from post in db.Posts
                   join ln in order on post.Lang equals ln.Name into lnPost
                   from od in lnPost.DefaultIfEmpty()
                   orderby od.Id
                   select post;
var data = orderedItems.ToList();

你可以找到BloggingContext here的定义我刚为语言代码添加了Lang字段。这将在SQLite,SqlServer和MySQL中用于oracle,您需要添加from dual 由于EF核心有多糟糕,您需要像使用SQL视图一样对OrderIndex执行相同的过程。在EF 6中,使用SqlQuery有一个更好的方法,你不需要像EF核心一样进行注册。 创建的查询是

SELECT "post"."PostId", "post"."BlogId", "post"."Content", "post"."Date", "post"."Lang", "post"."Title", "ln"."Id", "ln"."Name"
    FROM "Posts" AS "post"
    LEFT JOIN (
        select 'FR' as Name,0 as Id union select 'EN' as Name,1 as Id
    ) AS "ln" ON "post"."Lang" = "ln"."Name"
    ORDER BY "ln"."Id", "post"."Lang"

编辑: 只记得采用不同的方式做到这一点,它不是那么疯狂,但可能会更好。

var lang = new List<string> { "FR", "EN" };    
var orderedItems = from post in db.Posts
                   orderby (lang[0] == post.Lang) ? 
                   0 :((lang[1] == post.Lang) ? 1 : 2)
                   select post;

var param = Expression.Parameter(typeof(Post));

var order = lang.Select((s, i) => new { s, i })
    .Aggregate((Expression)Expression.Constant(lang.Count), (agg, i) =>
        Expression.Condition(
            Expression.Equal(Expression.Property(param,nameof(Post.Lang)),
            Expression.Constant(i.s)),
            Expression.Constant(i.i),
            agg));
var exp = Expression.Lambda<Func<Post, int>>(order, param);
var data = db.Posts.OrderBy(exp).ToList();

和SQL

SELECT "p"."PostId", "p"."BlogId", "p"."Content", "p"."Date", "p"."Lang", "p"."Title"
    FROM "Posts" AS "p"
    ORDER BY CASE
        WHEN "p"."Lang" = 'EN'
        THEN 1 ELSE CASE
            WHEN "p"."Lang" = 'FR'
            THEN 0 ELSE 2
        END
    END

我仍然认为疯狂的方式对于我不知道的事情是有用的。