【问题标题】:Insert enum as string using Dapper.Contrib使用 Dapper.Contrib 将枚举作为字符串插入
【发布时间】:2017-08-29 14:45:28
【问题描述】:

我刚刚开始使用 Dapper.Contrib 来帮助我进行插入和获取,但是由于我的枚举作为字符串存储在数据库中(出于多种原因),我在插入时遇到了问题。 Dapper 在读取时与字符串枚举无缝协作,但插入总是会将序数值放入数据库。

为此,我已经阅读了许多向 Dapper 提出的建议,并且打开了很多问题,但没有找到可行的解决方案。我的简化类如下所示:

public class Person {
  public long Id { get; set; }
  public string Name { get; set; }
  public Gender Gender { get; set; }
}

public enum Gender { Female, Male, TransWoman, TransMan }

我希望我可以配置 Dapper.Contrib 以使用枚举名称而不是序号值发出插入,这样下面的代码就会神奇地工作并在 varchar(20) 数据库字段性别中插入“男性”:

void InsertPersonFelipe(SqlConnection conn) {
  var person = new Person { Name = "Felipe", Gender = Gender.Male };
  conn.Insert(person);
}

有没有办法为typeof(Gender) 添加自定义映射?

或者,更好的是,Dapper.Contrib 是否提供了一种配置以使其使用枚举名称而不是它们的序数值?

【问题讨论】:

  • 嘿@Loudenvier,你找到办法了吗?
  • @rsilva 我已经放弃了这个,并且开始手动编写我的插入而不是使用 Dapper.Contrib,然后我只使用我的枚举 ToString 方法......它不是这样的对我来说很重要,但如果有人回答这个会很好;-)
  • 感谢您的回复@Loudenvier!

标签: c# enums dapper dapper-contrib


【解决方案1】:

我编写了一个扩展方法来处理将枚举转换为字符串,并考虑了 Dapper.Contrib 中的 Table 和 Computed 属性。如果您不想引用 Dapper.Contrib,也可以轻松删除这些内容。

用法:

  using (var sql = new SqlConnection(_connString))
  {
      sql.Open();
      sql.InsertB(person);
  }

扩展方法:

    public static long InsertB<T>(this SqlConnection sqlConnection, T obj)
    {
        Dictionary<string, object> propertyValuesMap = new Dictionary<string, object>();

        var columns = new StringBuilder();
        var values = new StringBuilder();
        var tableName = ((TableAttribute)obj.GetType().GetCustomAttribute(typeof(TableAttribute))).Name;
        var relevantProperties = obj.GetType().GetProperties().Where(x => !Attribute.IsDefined(x, typeof(ComputedAttribute))).ToList();

        for (int i = 0; i < relevantProperties.Count(); i++)
        {
            object val = null;
            var propertyInfo = relevantProperties[i];
            if (propertyInfo.PropertyType.IsEnum)
            {
                val = Enum.GetName(propertyInfo.PropertyType, propertyInfo.GetValue(obj));
            }
            else
            {
                val = propertyInfo.GetValue(obj);
            }

            propertyValuesMap.Add(propertyInfo.Name, val);
            var propName = i == relevantProperties.Count() - 1 ? $"{propertyInfo.Name}" : $"{propertyInfo.Name},";
            columns.Append(propName);
            values.Append($"@{propName}");
        }

        return sqlConnection.Execute($"Insert Into {tableName} ({columns}) values ({values})", propertyValuesMap);
    }

【讨论】:

  • 你需要排除集合和非原始类型属性吗?
【解决方案2】:

我将 Dan 的答案改写为更现代的 C# 并且不尝试插入 ID(因为我有自动递增的标识列),以及采用表名而不是查看属性。

    public static long InsertB<T>(this SqlConnection sqlConnection, T obj, string tableName)
    {
        Dictionary<string, object> propertyValuesMap = new Dictionary<string, object>();
        var columnList = new List<String>();
        var valueList = new List<String>();
        var relevantProperties = obj.GetType().GetProperties().Where(x => !Attribute.IsDefined(x, typeof(ComputedAttribute))).ToList();

        foreach (var propertyInfo in relevantProperties)
        {
            if (propertyInfo.Name.ToLower() == "id") continue; // do not try to insert id
            
            var val = propertyInfo.PropertyType.IsEnum
                ? Enum.GetName(propertyInfo.PropertyType, propertyInfo.GetValue(obj))
                : propertyInfo.GetValue(obj);
            
            propertyValuesMap.Add(propertyInfo.Name, val);
            columnList.Add(propertyInfo.Name);
            valueList.Add($"@{propertyInfo.Name}");
        }

        return sqlConnection.Execute($"Insert Into {tableName} ({String.Join(", ", columnList)}) values ({String.Join(", ", valueList)})", propertyValuesMap);
    }

【讨论】:

    猜你喜欢
    • 2015-12-19
    • 2011-10-03
    • 1970-01-01
    • 1970-01-01
    • 2020-01-15
    • 1970-01-01
    • 1970-01-01
    • 2010-10-03
    相关资源
    最近更新 更多