3

我已经使用Dapper.NET了一段时间了。我只是想知道是否可以让 Dapper 在将字符串分配给对象的属性时修剪字符串。

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

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

我自己编辑了 dapper 的源代码,但最终破坏了其他映射等,所以放弃了。

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

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

4

3 回答 3

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 相同的名称)是扩展方法解析的工作原理,您可以在此处阅读。

于 2015-04-10T00:11:38.107 回答
1

我假设您想要一种更自然的方式来通过 POCO 暗示 LTRIM(RTRIM()) 函数,这样您就不需要每次想要返回该字段时手动输入 LTRIM(RTRIM()) ,给出无需人工重复劳动即可获得 SQL 性能。

我有两个选择:

在 Dapper-Dot-Net 方面:

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

  • 如果查询中有多个表,我会认为这超出了范围
  • 否则,我相信这可以很容易地完成,而不会破坏 Dapper 引擎的其余部分。

过程:

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

在 SQL 端:

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

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

UpdateTableView(tableName): 1. 如果没有 char 字段则退出 2. 使用 cast(LTRIM(RTRIM(..)) as varchar(CHAR_FIELD_SIZE) 自动创建视图

于 2013-03-16T04:03:48.860 回答
1

马特,

这可以很容易地完成。我做了这个改变来清理 SQL 字符空间。我已经对其进行了测试,如果由于更改而变慢,我的代码没有任何迹象。

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

接下来创建以下方法:

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

编译,你准备好了

于 2014-04-26T20:42:13.313 回答