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的解决方案,这样数据库中就不会有翻译。