使用Dapper.NET修剪字符串

时间:2013-03-15 15:52:46

标签: c# sql dapper

我一直在使用Dapper.NET一段时间了。我只是想知道是否有可能让Dapper修剪字符串,因为它将它们分配给对象的属性。

我目前在SQL中使用LTRIM(RTRIM(fieldname)),在属性设置器中使用value.Trim()

然而,我正在使用使用chars而不是varchar的遗留数据库,我想知道是否有办法减少我必须修剪所有内容的时间。

我通过编辑dapper的源代码来完成自己,但最终打破了其他映射等所以放弃了。

只是想知道是否有人有任何可以减少这种开销的建议。 (我可能会遗漏一些非常简单的东西!)

顺便说一句,我正在使用C#3.5。

3 个答案:

答案 0 :(得分:7)

我不喜欢直接修改Dapper的想法。我决定通过创建一个扩展方法来解决问题,以包装Dapper,并只反映结果并修剪所有字符串属性。

public static class DapperExtensions {
    public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) {
        var dapperResult = SqlMapper.Query<T>(cnn, sql, param, transaction, buffered, commandTimeout, commandType);
        var result = TrimStrings(dapperResult.ToList());
        return result;
    }

    static IEnumerable<T> TrimStrings<T>(IList<T> objects) {
        //todo: create an Attribute that can designate that a property shouldn't be trimmed if we need it
        var publicInstanceStringProperties = typeof (T).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.PropertyType == typeof (string) && x.CanRead &&  x.CanWrite);
        foreach (var prop in publicInstanceStringProperties) {
            foreach (var obj in objects) {
                var value = (string) prop.GetValue(obj);
                var trimmedValue = value.SafeTrim();
                prop.SetValue(obj, trimmedValue);
            }
        }
        return objects;
    }

    static string SafeTrim(this string source) {
        if (source == null) {
            return null;
        }
        return source.Trim();
    }
}

我的解决方案至关重要(因为我想使用与Dapper相同的名称)是扩展方法解析的工作原理,您可以阅读here

答案 1 :(得分:1)

我假设你想要一种更自然的方式来通过你的POCO暗示LTRIM(RTRIM())函数,这样你每次想要返回时都不需要手动输入LTRIM(RTRIM())字段,在没有手动重复劳动的情况下为您提供SQL性能。

我有两种选择:

在Dapper-Dot-Net方面:

您可以在查询功能阶段添加一些代码,在原始SQL查询上执行替换算法。

  • 如果查询中有多个表,我会认为这超出了范围
  • 否则我相信这可以很容易地完成,而不会破坏其他的精密发动机。

过程:

  • 首先在你的桌面名称上执行一个无知的IndexOf,忽略大小写,这样你可以快速传递,如果不是的话。
  • 如果找到了表名,则对查询执行更可靠的分析,确保您找到的表名实际上是查询中的表名。在这里,您还可以确保查询中只有一个表,并且没有联接。
  • 如果选择中有*,则可以根据您的poco定义将其扩展为字段名称
  • 所以现在你只需要在你选择的阵容中添加字段
  • 对于所有字段,在选择系列中,在poco定义中找到名称,其中有[Trim]属性,将字段名称替换为LTRIM(RTRIM({FieldName}))为[{FieldName} ]

在SQL端:

如果您有权在服务器上创建视图,那么您可以编写存储过程来创建/更改(更新)一组视图,这些视图公开了char字段的varchar接口。

批量更新 - 每次有架构更改时运行此命令: 1.遍历所有用户表 2.创建或更新相应的视图

UpdateTableView(表名): 1.如果没有字段,则退出 2.使用强制转换(LTRIM(RTRIM(...))作为varchar(CHAR_FIELD_SIZE)自动创建视图

答案 2 :(得分:1)

马特,

这可以很容易地完成。我做了这个更改来清理SQL char空间。我测试了它,我的代码显示没有迹象表明由于变化导致的缓慢。

首先确保您备份现有的源代码,以便在需要时更容易恢复。

下一步创建以下方法:

public static string ReadString(object value) /*** CUSTOM CODE ***/
{
    if (value == null || value is DBNull) return null; 
    return value.ToString().Trim();
}

我总是用/ * CUSTOM CODE * /标记我的所有代码更改,以便稍后我可以轻松找到我的更改

下一步找到以下方法:

public static void SetTypeMap(Type type, ITypeMap map)

现在在该方法中找到以下行:

if (memberType == typeof (char) || memberType == typeof (char?))
{
    il.EmitCall(OpCodes.Call, typeof (SqlMapper).GetMethod(
        memberType == typeof (char) ? "ReadChar" : "ReadNullableChar",
        BindingFlags.Static | BindingFlags.Public), null);
        // stack is now [target][target][typed-value]
}
else

并修改如下:

if (memberType == typeof (char) || memberType == typeof (char?))
{
    il.EmitCall(OpCodes.Call, typeof (SqlMapper).GetMethod(
        memberType == typeof (char) ? "ReadChar" : "ReadNullableChar",
        BindingFlags.Static | BindingFlags.Public), null);
        // stack is now [target][target][typed-value]
}
else if (memberType == typeof(string)) /*** CUSTOM CODE START ***/
{
    il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod("ReadString", BindingFlags.Static | BindingFlags.Public), null);
    // stack is now [target][target][typed-value]
}    /*** CUSTOM CODE END ***/
else

编译,你准备好了