Flash_Back Flash_Back - 1 month ago 7
C# Question

Linq expression for ordering entities based on static values

I'm working on an ASP.NET MVC project using EF code first and I would need to build a

Linq expression
in order to order
Item
entities based on a static dictionary values.

public partial class Item
{
public enum TypeE
{
Type1,
Type2,
Type3,
Type4,
}

public TypeE Type { get; set; } // Mapped database column

public static Dictionary<TypeE, int> MyDic = new Dictionary<TypeE, int>()
{
{ TypeE.Type1, 42 },
{ TypeE.Type2, 16 },
{ TypeE.Type3, 0 },
{ TypeE.Type4, 34 },
};
}


My final aim would be some method working in
Linq to entities
and that would allow me to achieve something like
myEntities.OrderBy(i => Item.MyDic[i.Type])
.

I've to precise that I can not use
AsEnumerable()
or anything else enumerating the entities collection, I really need something working directly in
Linq to entities
.

I also would like to avoid creating reference tables in the database, I'm really looking for a
Linq expression
.

A few days ago, I asked a quite similar question about how to sort entities by an enum description and the answer given by Ivan Stoev (http://stackoverflow.com/a/40203664/2828106) perfectly achieved what I wanted.

If there was a way to reuse this kind of logic for this new purpose this would be great but I was not experimented enough, I ended up with an infinite loop while trying.

Thanks a lot.

Answer

Here is the same approach utilized for dictionary:

public static class Expressions
{
    public static Expression<Func<TSource, int>> DictionaryOrder<TSource, TKey, TOrder>(Expression<Func<TSource, TKey>> source, IReadOnlyDictionary<TKey, TOrder> by)
    {
        var body = by
            .OrderBy(entry => entry.Value)
            .Select((entry, ordinal) => new { entry.Key, ordinal })
            .Reverse()
            .Aggregate((Expression)null, (next, item) => next == null ? (Expression)
                Expression.Constant(item.ordinal) :
                Expression.Condition(
                    Expression.Equal(source.Body, Expression.Constant(item.Key)),
                    Expression.Constant(item.ordinal),
                    next));

        return Expression.Lambda<Func<TSource, int>>(body, source.Parameters[0]);
    }
}

and the sample usage:

var order = Expressions.DictionaryOrder((Item x) => x.Type, Item.MyDic);