当我使用 EF (System.Data.Entity) 时,我成功地使用了一个拦截器来自动修剪数据库中所有现有的字符串。
IDbCommandTreeInterceptor 在这篇文章中进行了描述:EF6.1 – 解决字符串连接中的尾随空白问题.
public class StringTrimmerInterceptor : IDbCommandTreeInterceptor
{
public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
{
if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace)
{
var queryCommand = interceptionContext.Result as DbQueryCommandTree;
if (queryCommand != null)
{
var newQuery = queryCommand.Query.Accept(new StringTrimmerQueryVisitor());
interceptionContext.Result = new DbQueryCommandTree(
queryCommand.MetadataWorkspace,
queryCommand.DataSpace,
newQuery);
}
}
}
private class StringTrimmerQueryVisitor : DefaultExpressionVisitor
{
private static readonly string[] _typesToTrim = { "nvarchar", "varchar", "char", "nchar" };
public override DbExpression Visit(DbNewInstanceExpression expression)
{
var arguments = expression.Arguments.Select(a =>
{
var propertyArg = a as DbPropertyExpression;
if (propertyArg != null && _typesToTrim.Contains(propertyArg.Property.TypeUsage.EdmType.Name))
return EdmFunctions.Trim(a);
return a;
});
return DbExpressionBuilder.New(expression.ResultType, arguments);
}
}
}
我需要一些帮助来通过 EntityFrameworkCore DbCommandInterceptor 实现相同的功能。
最后我不得不自己找到解决方案。
首先,我通过以下方式实现了抽象类DbDataReader:
public class TrimStringsDataReader : DbDataReader
{
private readonly DbDataReader _innerReader;
public TrimStringsDataReader(DbDataReader innerReader)
{
_innerReader = innerReader;
}
public override string GetString(int ordinal)
{
var value = _innerReader.GetString(ordinal);
#pragma warning disable CS8603 // Possible null reference return.
return value?.Trim();
#pragma warning restore CS8603 // Possible null reference return.
}
public override object GetValue(int ordinal)
{
var value = _innerReader.GetValue(ordinal);
if (value is string stringValue)
value = stringValue.Trim();
return value;
}
public override object this[int ordinal] => _innerReader[ordinal];
public override object this[string name] => _innerReader[name];
public override int Depth => _innerReader.Depth;
public override int FieldCount => _innerReader.FieldCount;
public override bool HasRows => _innerReader.HasRows;
public override bool IsClosed => _innerReader.IsClosed;
public override int RecordsAffected => _innerReader.RecordsAffected;
public override bool GetBoolean(int ordinal) => _innerReader.GetBoolean(ordinal);
// And so on all the other methods
}
然后我覆盖了DbCommandInterceptor类:
public class TrimStringsInterceptor : DbCommandInterceptor
{
public override DbDataReader ReaderExecuted(
DbCommand command,
CommandExecutedEventData eventData,
DbDataReader result)
{
result = new TrimStringsDataReader(result);
return base.ReaderExecuted(command, eventData, result);
}
public override ValueTask<DbDataReader> ReaderExecutedAsync(
DbCommand command,
CommandExecutedEventData eventData,
DbDataReader result,
CancellationToken cancellationToken = default)
{
result = new TrimStringsDataReader(result);
return base.ReaderExecutedAsync(command, eventData, result, cancellationToken);
}
}
以这种方式,EF Core 实例化传递给 ReaderExecuted/Async 的 DbDataReader 具体类(它取决于驱动程序,即在 SqlServer 的情况下是 Microsoft.Data.SqlClient.SqlDataReader),因此我可以使用真正的阅读器“装饰“用我的修剪字符串行为。