gpt4 book ai didi

c# - 按枚举描述排序

转载 作者:行者123 更新时间:2023-11-30 13:36:05 30 4
gpt4 key购买 nike

我首先使用 EF 代码开发 ASP.NET MVC projet,我面临着需要通过枚举描述进行排序的情况:

public partial class Item
{
public enum MyEnumE
{
[Description("description of enum1")]
Enum1,
[Description("description of enum2")]
Enum2,
...
}

public MyEnumE MyEnum { get; set; }
}

这是 SearchSortAndPaginate 函数:

public async Task<IPagedList<Item>> Search(ItemCriteria criteria, SortableTypeE sortName, SortOrder.TypeE sortOrder, int pageNb)
{
var itemFilter = GenerateFilter(criteria);
var items = entities.Items.Where(itemFilter);

return await SortAndPaginate(items, sortName, sortOrder, pageNb);
}

private async Task<IPagedList<Item>> SortAndPaginate(IQueryable<Item> items, SortableTypeE sortName, SortOrder.TypeE sortOrder, int pageNb)
{
IOrderedQueryable<Item> result = null;

switch (sortName)
{
...
case SortableTypeE.Type:
result = sortOrder == SortOrder.TypeE.ASC
? items.OrderBy(i => i.MyEnum.GetDescription())
: items.OrderByDescending(i => i.MyEnum.GetDescription());
result = result.ThenBy(i => i.SomeOtherProperty);
break;
...
}

if (result != null)
{
return await result.ToPagedListAsync(pageNb, 10);
}

return PagedListHelper.Empty<Item>();
}

问题是 Item 表可能非常大。
我考虑过在 entities.Items.Where(itemFilter) 之后立即调用 ToListAsync 但这将取回所有过滤的项目,尽管我只需要一页。听起来不是个好主意。

但如果我不这样做,EF 将不知道 GetDescription() 方法,我只能考虑两个解决方案:
- 将我的数据库列更改为字符串(枚举描述)而不是枚举本身(但对我来说听起来像是 hack)
- 或者直接在 enum 声明中按字母顺序排列 MyEnumE 组件(看起来很脏而且也很难维护)

如果我在过滤后立即调用 ToListAsync,我很担心性能,所以我很困惑,所有其他解决方案看起来都很脏,我绝对需要返回一个 IPagedList来自 Search 方法。

有人知道如何处理这个问题吗?

非常感谢。

更新

这里是GetDescription方法(必要时可以更改):

public static string GetDescription(this Enum e)
{
FieldInfo fi = e.GetType().GetField(e.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Length > 0)
return attributes[0].Description;
else
return e.ToString();
}

解决方案

我最终会采纳 Ivan Stoev 的建议,因为我的项目主要基于 Linq(使用 Linq 而不是存储过程等),所以这个解决方案似乎更比创建引用表更适合我的特殊情况。

然而,Niyoko YuliawanMichael Freidgeim 对我来说也是很好的答案,任何阅读这篇文章并拥有更多数据库方法的人都应该寻求他们的解决方案;)

非常感谢大家。

最佳答案

我会选择动态表达。它更灵活,可以轻松更改而不影响数据库表和查询​​。

但是,我不按数据库中的描述字符串排序,而是在内存中创建有序映射,将 int“order”值与每个枚举值相关联,如下所示:

public static class EnumHelper
{
public static Expression<Func<TSource, int>> DescriptionOrder<TSource, TEnum>(this Expression<Func<TSource, TEnum>> source)
where TEnum : struct
{
var enumType = typeof(TEnum);
if (!enumType.IsEnum) throw new InvalidOperationException();

var body = ((TEnum[])Enum.GetValues(enumType))
.OrderBy(value => value.GetDescription())
.Select((value, ordinal) => new { value, ordinal })
.Reverse()
.Aggregate((Expression)null, (next, item) => next == null ? (Expression)
Expression.Constant(item.ordinal) :
Expression.Condition(
Expression.Equal(source.Body, Expression.Constant(item.value)),
Expression.Constant(item.ordinal),
next));

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

public static string GetDescription<TEnum>(this TEnum value)
where TEnum : struct
{
var enumType = typeof(TEnum);
if (!enumType.IsEnum) throw new InvalidOperationException();

var name = Enum.GetName(enumType, value);
var field = typeof(TEnum).GetField(name, BindingFlags.Static | BindingFlags.Public);
return field.GetCustomAttribute<DescriptionAttribute>()?.Description ?? name;
}
}

用法是这样的:

case SortableTypeE.Type:
var order = EnumHelper.DescriptionOrder((Item x) => x.MyEnum);
result = sortOrder == SortOrder.TypeE.ASC
? items.OrderBy(order)
: items.OrderByDescending(order);
result = result.ThenBy(i => i.SomeOtherProperty);
break;

这会生成这样的表达式:

x => x.MyEnum == Enum[0] ? 0 :
x.MyEnum == Enum[1] ? 1 :
...
x.MyEnum == Enum[N-2] ? N - 2 :
N - 1;

其中 0,1,..N-2 是按描述排序的值列表中的相应索引。

关于c# - 按枚举描述排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40202415/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com