Order column by a separate `List` variable

前端 未结 2 1085
执笔经年
执笔经年 2020-12-12 06:16

I need to sort the results of an entity framework query by the index of elements in another list.

I tried the suggestion found elsewhere, like

.Then         


        
相关标签:
2条回答
  • 2020-12-12 06:32

    Here is a mad way to do it but it doesn't fall back to 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();
    

    You can find the definition of the BloggingContext here I just added a Lang field for a language code. This will work in SQLite, SqlServer and MySQL for oracle you need to add from dual Due to how terrible EF core is you will need to go true the same procedure for OrderIndex as you would with an SQL view. In EF 6 there is a much nicer way of doing this with SqlQuery and you don't need to do the registration like with EF core. The created query is

    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"
    

    EDIT: Just remembered a different way to do it it's not as mad but might be better.

    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();
    

    And the 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
    

    I still think the mad way is useful for something I just don't know what.

    0 讨论(0)
  • 2020-12-12 06:47

    this should do the trick:

    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));
    }
    
    0 讨论(0)
提交回复
热议问题