【问题标题】:How to sort enum column in nHibernate with display name of enum type如何使用枚举类型的显示名称对 nHibernate 中的枚举列进行排序
【发布时间】:2021-04-27 20:17:20
【问题描述】:

我有一个表Email,其中有一列EmailTypeEmailType 是 nHibernate 中的枚举,在 DB 中存储为 int。我也有扩展方法来获取电子邮件类型的名称:

namespace Email
{
    public enum EmailType : int
    {
        PasswordReset = 0,
        EmailVerification = 1,
        AccountCreation = 2
    };

    public static class EmailType Extension
    {
      public static string Name(this EmailType self)
      {
        switch (self)
        {
          case EmailType.PasswordReset :
            return "Password Reset";
          case EmailType.EmailVerification :
            return "Email Verification";
          case EmailType.AccountCreation :
            return "Account Creation";
          default:
            return null;
        }
      }
    }
}

然后我可以使用EmailType.PasswordReset.Name()获取枚举的名称

我正在通过创建 nHibernate 标准来获取电子邮件列表:

var criteria = session.CreateCriteria<Email>();
criteria.SetFirstResult(startIndex).SetMaxResults(maxResults);
criteria.AddOrder(Order.Asc("EmailType"));
return criteria.List<Email>();

问题在于它使用存储在 DB 中的 EmailType int 对行进行排序。有没有什么办法可以使用EmailType枚举的EmailType.PasswordReset.Name()扩展方法以枚举的名称排序?

【问题讨论】:

    标签: c# .net nhibernate


    【解决方案1】:

    由于您按字母顺序排列的枚举(在本例中)将由 2、1、0 表示,因此您可以按相反的顺序对 EmailType 进行排序,这样就可以得到您想要的。

    criteria.AddOrder(Order.desc("EmailType"));
    

    但是,正如您所说,“这是一个巧合”。

    它不能对枚举名称进行排序的原因是它不知道它们是什么,所以你需要找到一种方法来告诉它。有两个:

    一种方法是添加一个计算字段,将枚举值转换为名称。我已经用其他数据库做到了这一点,我相信 @Formula 是你在 Hibernate 中使用的。

    另一种方法是在您的数据库中创建另一个包含枚举数和枚举值的表。然后将查询中的两个表链接起来,这样就可以返回枚举值了。

    在任何一种情况下,您都将排序应用于新字段。

    【讨论】:

    • 这很巧合:)。我在这里给出的这些名字只是少数几个。所有名称都不会按字母顺序排列。然后我也有框架来返回不同语言的翻译名称。
    • 我会提取数据然后对其进行排序。
    【解决方案2】:

    我遇到了同样的问题,我找到了一种使用投影的方法

    QueryOver<TRoot, TSubType>.OrderBy(IProjection projection)
    

    queryOver
        .OrderBy(GetOrderByEnumProjection<TSubType, MyEnum>(x => x.EnumProperty, GetAllMyEnumValuesSortedByDisplayName(CultureInfo.CurrentCulture)));
    
    private static IProjection GetOrderByEnumProjection<TObject, TEnum>(Expression<Func<TObject, object>> enumProperty, IReadOnlyList<TEnum> enumValues)
        where TEnum : Enum
    {
        int index = enumValues.Count - 1;
    
        TEnum enumValue = enumValues[index];
    
        IProjection elseProjection = GetConditional(enumProperty, enumValue, index, Projections.Constant(-1));
    
        for (index = enumValues.Count - 2; index >= 0; index--)
        {
            enumValue = enumValues[index];
    
            elseProjection = GetConditional(enumProperty, enumValue, index, elseProjection);
        }
    
        return elseProjection;
    }
    
    private static IProjection GetConditional<TObject, TEnum>(Expression<Func<TObject, object>> enumProperty, TEnum value, int sortIndex, IProjection elseProjection)
        where TEnum : Enum
    {
        return Projections.Conditional(
            Restrictions.Eq(Projections.Property<TObject>(enumProperty), value),
            Projections.Constant(sortIndex),
            elseProjection);
    }
    

    (您可以在此处找到有关生成的 SQL 外观的更多详细信息:Adding more than one condition in Projection.Conditionals for queryover。)

    【讨论】:

    • 原来条件的嵌套是不能无休止的。在MsSql 中支持19 之类的。SqlLite 就更少了。需要找到一种方法让 NH 使用 'case 当 this_.Name == 'A' 然后 1 当 this_.Name == 'B' 然后 2 当 this_.Name == 'C' 然后 3 [...] else 0'。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多