C# 基于语言的枚举列排序

C# 基于语言的枚举列排序,c#,entity-framework,C#,Entity Framework,假设我有以下简单的设置: public enum Status { Pending = 0, Accepted = 1, Rejected = 2 } public class MyEntity { public Status Status { get; set; } } …我希望对两种不同语言的状态进行以下升序排序: Language 1: 1, 0, 2 Language 2: 0, 1, 2 在实体框架中有没有一种简单的方法来实现这一点?我觉得这可能

假设我有以下简单的设置:

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

public class MyEntity
{
    public Status Status { get; set; }
}
…我希望对两种不同语言的
状态
进行以下升序排序:

Language 1: 1, 0, 2
Language 2: 0, 1, 2
在实体框架中有没有一种简单的方法来实现这一点?我觉得这可能是一种常见的情况


我认为唯一的办法是维护一个单独的表,其中包含状态的所有翻译。。。然后根据用户的当前语言,按该表中的“名称”列进行排序。不过,我想看看是否有人有其他想法。

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

如果您想要某种自定义排序器,您必须编写自己的并在内存中排序


我不太确定我是否理解您的单独表概念,您能否提供更多详细信息。

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

如果您想要某种自定义排序器,您必须编写自己的并在内存中排序


我不太确定我是否理解您的独立表概念,您能否提供更多详细信息。

您可以编写一个查询,而不需要单独的表,但它并不漂亮。也不是很灵活。由于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;
    }

}
其输出如下:

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

您可以编写一个查询,而不需要单独的表,但它并不漂亮。也不是很灵活。由于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;
    }

}
其输出如下:

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

我接受了西蒙的回答,因为这是我在问题中提到的另一种选择。这里有一个方法,我想出了如何用一个单独的工作表。明显的缺点是您必须在数据库中维护翻译

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

我从来没有编译过这个示例代码(只有我自己的代码),因此我对任何错误表示歉意,但它应该能很好地表达我的想法。

我接受Simon的答案,因为它是我在问题中提到的另一种选择。这里有一个方法,我想出了如何用一个单独的工作表。明显的缺点是您必须在数据库中维护翻译

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

我从来没有编译过这个示例代码(只有我自己的代码),因此我为任何错误表示歉意,但它应该能很好地表达我的想法。

Ben,我在a中概述了表格想法。Ben,我在a中概述了表格想法。我更喜欢Simon基于表达式的解决方案。您的结果是匿名类型列表,它不如Simon的灵活,Simon的返回和OrderedQueryable您的实际实体。它更易读,也更容易理解。最后一个原因可能是缺点,也可能不是缺点,它不需要一个好的新表,但映射是在代码中的,因此添加一种新语言需要代码更改。除非您真的需要在DB中存储语言映射的灵活性,否则我会说Simon的解决方案的前两个优点超过了您的。Ben,感谢您的输入!为了简洁起见,该示例使用匿名类型。在我的实际代码中,我正在创建一个已定义类的新实例(我也不喜欢匿名类型)。要返回OrderedQueryable,只需关闭
.ToList()
。在我的例子中,我所在的公司一直在存储过程中使用转换表,以便在ASP.NET gridview中显示。。。所以介绍一个新的桌子并不是什么大事。无论如何,如果这是我自己的项目,我会使用Simon的解决方案,以避免数据库中出现翻译。我更喜欢Simon的基于表达式的解决方案。您的结果是匿名类型列表,它不如Simon的灵活,Simon的返回和OrderedQueryable您的实际实体。它更易读,也更容易理解。最后一个原因可能是缺点,也可能不是缺点,它不需要一个好的新表,但映射是在代码中的,因此添加一种新语言需要代码更改。除非您真的需要在DB中存储语言映射的灵活性,否则我会说Simon的解决方案的前两个优点超过了您的。Ben,感谢您的输入!为了简洁起见,该示例使用匿名类型。在我的实际代码中,我正在创建一个已定义类的新实例(我也不喜欢匿名类型)。要返回OrderedQueryable,只需关闭
.ToList()
。在我的例子中,我所在的公司一直在存储过程中使用转换表,以便在ASP.NET gridview中显示。。。所以介绍一个新的桌子并不是什么大事。无论如何,如果这是我自己的项目,我会使用Simon的解决方案,这样数据库中就不会有翻译。