当前位置: 首页 > 知识库问答 >
问题:

将不同枚举映射在一起

刁文光
2023-03-14

首先,这就是为什么这个问题不是重复的:

我知道在SO上已经问了很多关于将一个枚举转换为另一个的问题,我甚至自己回答了其中一个问题,但是我在这个主题上发现的所有问题都有一些比较不同枚举值的方法(无论是通过名称还是按价值)。在我的特殊情况下,我不知道值,名字也不匹配。

作为我正在做的一个名为ADONETHelper的GitHub项目的一部分,该项目旨在最大限度地减少与Ado一起工作时的代码重复。Net中,我面对面地需要在不相关的枚举之间转换值。这是为了允许相同的代码与OleDb、Odbc和SqlClient一起工作(希望将来也能使用OracleClient和MySqlClient)。

我试图做的是创建不同枚举的统一——特别是——描述sql参数数据类型的枚举。确切地说,我支持4个枚举-
System.数据。DbType
System.数据。SqlClient.SqlDbType
System.数据。OleDb.OleDbType
System.数据。Odbc。OdbcType

但如果我想添加对OracleClient或MySqlClient的支持,我必须非常努力地添加系统。数据OracleClient。OracleTypeMySql。数据MySqlClient。MySqlDbType。因此,我正在寻找一种更优雅的方法,然后我想出了。

以下是我当前的代码(它工作得很好,但正如我所写,很难添加对新枚举的支持):

首先,我定义了自己的枚举,称为ADONETType。它具有诸如布尔Byte二进制Char等条目。然后,我创建了一个名为DBTypeConzer的静态类,为此枚举提供扩展方法,以便将其值转换为其他枚举。这就是这个类的样子:

internal static class DBTypeConverter
{
    #region private members

    private static List<DbTypeMap> _Map;

    #endregion private members

    #region static constructor

    static DBTypeConverter()
    {
        _Map = new List<DbTypeMap>()
        {
            new DbTypeMap(ADONETType.Boolean, DbType.Boolean, SqlDbType.Bit, OleDbType.Boolean, OdbcType.Bit),
            new DbTypeMap(ADONETType.Byte, DbType.Byte, SqlDbType.TinyInt, OleDbType.UnsignedTinyInt , OdbcType.TinyInt),
            new DbTypeMap(ADONETType.Binary, DbType.Binary, SqlDbType.Binary, OleDbType.Binary, OdbcType.Binary),
            // ... more of the same here ...                
            new DbTypeMap(ADONETType.Xml, DbType.Xml, SqlDbType.Xml, null, null)
        };
    }

    #endregion static constructor

    #region methods

    internal static DbType ToDbType(this ADONETType type)
    {
        return type.ConvertTo<DbType>();
    }

    internal static SqlDbType ToSqlType(this ADONETType type)
    {
        return type.ConvertTo<SqlDbType>();
    }

    internal static OleDbType ToOleDbType(this ADONETType type)
    {
        return type.ConvertTo<OleDbType>();
    }

    internal static OdbcType ToOdbcType(this ADONETType type)
    {
        return type.ConvertTo<OdbcType>();
    }

    private static dynamic ConvertTo<T>(this ADONETType type)
    {
        var returnValue = _Map.First(m => m.ADONETType == type).GetValueByType(typeof(T));
        if(returnValue != null)
        {
            return returnValue;
        }
        throw new NotSupportedException(string.Format("ADONETType {0} is not supported for {1}", type, typeof(T)));
    }

    #endregion methods

    #region private struct

    private struct DbTypeMap
    {
        #region ctor

        public DbTypeMap(ADONETType adonetType, DbType? dbType, SqlDbType? sqlDbType, OleDbType? oleDbType, OdbcType? odbcType)
            : this()
        {
            ADONETType = adonetType;
            DbType = dbType;
            SqlDbType = sqlDbType;
            OleDbType = oleDbType;
            OdbcType = odbcType;
        }

        #endregion ctor

        #region properties

        internal ADONETType ADONETType { get; private set; }
        internal DbType? DbType { get; private set; }
        internal SqlDbType? SqlDbType { get; private set; }
        internal OleDbType? OleDbType { get; private set; }
        internal OdbcType? OdbcType { get; private set; }

        #endregion properties

        #region methods

        internal dynamic GetValueByType(Type type)
        {
            if (type == typeof(ADONETType))
            {
                return this.ADONETType;
            }
            if(type == typeof(DbType))
            {
                return this.DbType;
            }
            if (type == typeof(SqlDbType))
            {
                return this.SqlDbType;
            }
            if (type == typeof(OleDbType))
            {
                return this.OleDbType;
            }
            if (type == typeof(OdbcType))
            {
                return this.OdbcType;
            }
            return null;
        }

        #endregion methods
    }

    #endregion private struct
}

现在,如您所见,为了提供对OracleClient的支持,我必须执行以下操作:

  1. DbTypeMap私有结构中为OracleType添加属性。
  2. DbTypeMap构造函数更改为也接受oracle类型。
  3. GetValueByType方法中向交换机添加另一个大小写。
  4. 将oracle类型添加到DBTypeConzer的静态构造html" target="_blank">函数中。
  5. 添加一个方法(内部静态OracleType ToOracleType(此ADONETType类型))到DBTypeConzer

很明显,这是一个很大的工作,我更愿意找到另一种方法来统一这些枚举,所以向新客户机添加支持会更容易<这是你的专长发挥作用的时候。

共有1个答案

彭宜人
2023-03-14

假设你真的需要这个(考虑Jeroen的评论,如果没有,那么你可以把它重用到其他地方...)你可以使用等价列表来简化事情。它只是一个数组列表,其中数组项是等价的。我使用数组而不是类,因为在添加新的等价时,我不需要html" target="_blank">添加属性和ctor参数。为了存储等价性,我使用了特殊的Enum基类,而且对象工作得很好(不需要,AFAIK,对于动态)。

然后,查找转换只需在这些列表中进行搜索(此处的代码比性能方面的代码更为明确):

public static TTo ConvertTo<TTo>(Enum value)
{
    var set = Mapping.FirstOrDefault(values => Array.IndexOf(values, value) != -1);
    if (set == null)
        throw new InvalidOperationException($"Value {value} is unknown");

    return (TTo)(object)set.First(x => x.GetType() == typeof(TTo));
}

根据需要填充映射列表,它可以定义为,例如:

private static List<Enum[]> Mapping = new List<Enum[]>
{
    new Enum[] { ADONETType.Byte, DbType.Byte, SqlDbType.TinyInt },
    new Enum[] { ADONETType.Boolean, DbType.Boolean, SqlDbType.Bit },
    new Enum[] { ADONETType.Binary, DbType.Binary, SqlDbType.Binary },
    new Enum[] { ADONETType.Xml, DbType.Xml },
};

注意丑陋的双铸(TTo)(对象)...一个更好的解决方案是受欢迎的。要支持新的等价,您仍然需要将所有枚举的值映射到这个表中,这很烦人,但只局限于一个地方。如果转换不可能(任何地方都没有定义valuevalue),或者没有已知的转换到TTo(例如最后一个DbType)。xml),然后抛出InvalidoperationExc0019。

 类似资料:
  • 我有一个实体,有一个枚举类型字段和一个具有相同枚举类型和字段名的DTO。 我使用modelMapper创建一个新对象,不需要额外的配置。 但在将dto映射到实体对象后,实体对象上的性别为空。 对象有性别,我已经检查了很多。 请帮我理解这个问题。

  • 问题内容: 我需要预先将未实现接口的枚举映射到现有数据库,该数据库使用将该枚举存储在与所有者类相同的表中。 在这种情况下应如何处理映射?持久化到数据库不会改变,因为实现该接口的所有枚举都将具有不同的值,但是我不确定应如何从数据库中检索对象(我是否需要自定义映射器,它将尝试实例化一个使用指定的enum类进行枚举吗?Hibernate本身是否支持此功能?)。 问题答案: 可以创建一个自定义(例如thi

  • 问题内容: Hibernate提供的注释支持使用或的两种类型的映射。当我们使用映射时,它使用的“名称” 而不是Enum的表示形式。在数据库列仅包含一个字符的情况下,这是一个问题。例如,我有以下枚举: 当我坚持枚举使用,即hibernate尝试在数据库中存储的值是开放的。但是,我的数据库列仅包含一个字符,因此会引发异常。 克服这个问题的一个办法是改变枚举类型持有单个字符(如,代替,)。但是,这降低了

  • 问题内容: 我需要预先将没有实现接口的枚举映射到现有数据库,该数据库使用将该枚举存储在与所有者类相同的表中。 在这种情况下应如何处理映射?持久化到数据库不会改变,因为实现该接口的所有枚举都将具有不同的值,但是我不确定应如何从数据库中检索对象(我是否需要自定义映射器,它将尝试实例化一个使用指定的enum类进行枚举吗?Hibernate是否本身支持此功能?)。 问题答案: 可以创建一个自定义(例如th

  • 问题内容: Hibernate提供的注释支持使用或两种类型的映射。当我们使用映射时,它使用的“名称” 而不是Enum 的表示形式。在数据库列仅包含一个字符的情况下,这是一个问题。例如,我有以下枚举: 当我坚持枚举使用,即休眠尝试在数据库中存储的值是开放的。但是,我的数据库列仅包含一个字符,因此会引发异常。 克服这个问题的一个办法是改变枚举类型持有单个字符(如,代替,)。但是,这降低了可读性。有什么

  • 我对的枚举有问题。在方法中有两个枚举:和。是内置的Spring枚举,它完美地从String转换为Enum: 但是当我打电话的时候 我阅读并测试了: 带枚举的Spring的@RequestParam Spring Boot能够接受枚举作为请求参数 枚举作为Spring Boot Rest中的请求参数 如何在RequestParm中将多个值转换为枚举? @RequestParam defaultval