根据语言对枚举列进行排序

时间:2014-03-11 16:34:13

标签: c# entity-framework

说我有以下简单的设置:

public enum Status
{
    Pending  = 0,
    Accepted = 1,
    Rejected = 2
}

public class MyEntity
{
    public Status Status { get; set; }
}

...我希望以下两种不同语言的Status升序排序:

Language 1: 1, 0, 2
Language 2: 0, 1, 2

在实体框架中有一种简单的方法吗?我觉得这可能是一种常见的情况。

我认为唯一的方法是维护一个单独的表,其中包含Status的所有翻译...然后根据用户当前语言按该表中的name列排序。我想知道是否有人有任何其他想法。

3 个答案:

答案 0 :(得分:2)

EF将根据您将枚举映射到的DB列的类型(可能是int)进行排序,因此它的排序方式与对int进行排序的方式相同。

如果你想要某种自定义分类器,你必须自己编写并在内存中排序。

不确定我理解你的单独表格概念,你能不能提供更多细节。

答案 1 :(得分:2)

你可以在没有单独的表的情况下编写查询,但它并不漂亮。它也不是很灵活。由于EF依赖于众所周知的方法来映射到等效的SQL函数,因此您无法插入自定义函数。但是,您可以使用let

手动设置订单
var query = from e in MyEntity
            let sortOrder = UserLanguage == Language1 // Handle Language 1 Sort
                                ? e.Status == Pending 
                                      ? 1 : e.Status == Accepted ? 0 : 2
                           : e.Status == Pending // Handle Language 2 sort
                               ? 0 : e.Status == Accepted ? 1 : 2                                                                
            orderby sortOrder
            select e

这只适用于两种语言。我能想到的另一种方法是自己编写表达式树。这样做的好处是可以拆分每种语言的逻辑。我们可以提取三元条件逻辑并将它们放在扩展静态类中。这是一个样子的样本:

public static class QuerySortExtension
{
    private static readonly Dictionary<string, Expression<Func<MyEntity, int>>> _orderingMap;
    private static readonly Expression<Func<MyEntity, int>> _defaultSort;

    public static IOrderedQueryable<MyEntity> LanguageSort(this IQueryable<MyEntity> query, string language)
    {
        Expression<Func<MyEntity, int>> sortExpression;
        if (!_orderingMap.TryGetValue(language, out sortExpression))
            sortExpression = _defaultSort;

        return query.OrderBy(sortExpression);
    }

    static QuerySortExtension()
    {
        _orderingMap = new Dictionary<string, Expression<Func<MyEntity, int>>>(StringComparer.OrdinalIgnoreCase) {
            { "EN", e => e.Status == Status.Pending ? 1 : e.Status == Status.Accepted ? 0 : 2 },
            { "JP", e => e.Status == Status.Pending ? 2 : e.Status == Status.Accepted ? 1 : 0 }
        };

        // Default ordering
        _defaultSort = e => (int)e.Status;
    }

}

您可以这样使用以下方法:

var entities = new[] { 
    new MyEntity { Status = Status.Accepted }, 
    new MyEntity { Status = Status.Pending }, 
    new MyEntity { Status = Status.Rejected } 
}.AsQueryable();

var query = from e in entities.LanguageSort("EN")
            select e;
var queryJp = from e in entities.LanguageSort("JP")
              select e;

Console.WriteLine("Sorting with EN");
foreach (var e in query)
    Console.WriteLine(e.Status);

Console.WriteLine("Sorting with JP");
foreach (var e in queryJp)
    Console.WriteLine(e.Status);

以下输出:

Sorting with EN
Accepted
Pending
Rejected
Sorting with JP
Rejected
Accepted
Pending

答案 2 :(得分:0)

我接受了西蒙的回答,因为它可以替代我在问题中提到的内容。这是一种方法,我想出了如何使用一个有效的单独表。明显的缺点是你必须在数据库中维护翻译......

public enum Status
{
    Pending  = 0,
    Accepted = 1,
    Rejected = 2
}

public class MyEntity
{
    public int    MyEntityID { get; set; }
    public Status Status     { get; set; }
}

public enum Language
{
    Language1 = 0,
    Language2 = 1
}

public class StatusTranslation
{
    public int      StatusTranslationID { get; set; }
    public Language Language            { get; set; }
    public Status   Status              { get; set; }
    public string   Name                { get; set; }
}

以任何方式将所有翻译插入SQL表:

INSERT INTO StatusTranslations (Language, Status, Name) VALUES (0, 0, "Pending")
// etc...
INSERT INTO StatusTranslations (Language, Status, Name) VALUES (1, 0, "En attendant")
// etc...

现在加入并排序:

var userLanguage = Language.Language1;
var results = db.MyEntities.Join(
                  db.StatusTranslations, 
                  e => e.Status, 
                  s => s.Status, 
                  (e, s) => new { MyEntity = e, Status = s }
            )
            .Where(e => e.Status.Language == userLanguage)
            .Select(e => new {
                 MyEntityID = e.MyEntity.MyEntityID
                 StatusName = e.Status.Name
            }).OrderBy(e => e.StatusName).ToList();

我从来没有编译过这个示例代码(只有我自己的代码)所以我为任何错误道歉,但它应该给出足够好的想法。