如何配置实体框架以自动修剪为映射到char(N)字段的特定列检索的值?

Sam*_*Sam 26 .net sql entity-framework trim entity-framework-6

我正在使用第三方数据库,其中所有文本值都存储为char(n).其中一些文本值是主键,而其他文本值只是普通的人类可读文本.对于后者,我希望自动修剪检索到的值.

我知道我可以添加Trim到我的所有LINQ to Entities查询中,但这很麻烦,不可靠且不可维护.我想以某种方式配置实体框架以自动修剪从特定列检索的值.

但是,我不知道该怎么做.我正在使用EF的流畅API.到目前为止,我最接近的想法是使用Trim方法调用创建其他属性以包装真实属性,但这很麻烦,但仍然不能很好地维护.我也希望在数据库而不是应用程序中进行修剪.

Stu*_*sie 36

Rowan Miller(微软实体框架项目经理)最近发布了一个使用拦截器的好解决方案.不可否认,这仅适用于EF 6.1+.他的文章是关于尾随连接字符串,但基本上,所应用的解决方案巧妙地删除尾随从所有的字符串属性的字符串在你的模型,自动,不会明显影响性能.

原创博文:解决字符串连接中的尾随空白问题

相关代码转发到这里,但我鼓励您阅读他的博客文章.(如果你使用EF,你应该阅读他的博客).

using System.Data.Entity.Core.Common.CommandTrees;
using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure.Interception;
using System.Linq;

namespace FixedLengthDemo
{
    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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Rowan继续说道:"现在我们有一个拦截器,我们需要告诉EF使用它.这最好通过基于代码的配置完成.我们可以将下面的类放在与我们的上下文相同的程序集/项目中,EF将选择它."

using System.Data.Entity;

namespace FixedLengthDemo
{
    public class MyConfiguration : DbConfiguration
    {
        public MyConfiguration()
        {
            AddInterceptor(new StringTrimmerInterceptor());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 请谨慎使用。我们部署了这个精确的解决方案,它使我们的网站因 CPU 使用率而瘫痪。Profiler 显示它是原因,删除它可以解决问题。我确定效果与特定于应用程序的工作负载有关,但请注意,这是一个非常占用 CPU 的解决方案。 (2认同)
  • @PHenry 如果您使用的是 Entity Framework Core,那么这个答案很可能不会适用,它相当特定于 EF 6.1+ 到 6.4。 (2认同)

Tot*_*eRo 19

如果您使用的是Entity Framework Core,则可以Conversion像这样使用:

entity.Property(e => e.Name)
             .HasConversion(
                new ValueConverter<string, string>(v => v.TrimEnd(), v => v.TrimEnd()));
Run Code Online (Sandbox Code Playgroud)


Pau*_*ith 11

在实体上使用带有支持字段的属性而不是自动属性.

在属性设置器中添加"Trim()",如下所示:

    protected string _name;
    public String Name
    {
        get { return this._name; }
        set { this._name = (value == null ? value : value.Trim()); }
    }
Run Code Online (Sandbox Code Playgroud)

我编写了自己的POCO生成器,它自动执行此操作,但如果您没有这样的选项,ReSharper可以像两次击键一样将自动属性的后备字段添加到自动属性中.只需为字符串执行此操作,您就可以执行全局(在文件范围内)查找/替换" = value;"和" = value.Trim();".

  • 从C#6.0开始,使用空条件运算符可以很好地简化setter:`set {this._name = value?.Trim(); }` (3认同)
  • 最好先检查null,这样我就这样做:set {_name =(value == null?null:value.Trim());} (2认同)

Ger*_*old 2

实体框架不提供挂钩来更改其编写 SQL 语句的方式,因此您无法告诉它从数据库中获取和修剪字符串字段。

可以在ObjectContext.ObjectMaterialized事件中修剪字符串属性,但我认为这会极大地影响性能。此外,对于特定属性执行此操作需要大量if-else代码(正如您打算做的那样)。但如果您想对几乎所有属性(例如键除外)执行此操作,则可能值得一试。switch

否则我会选择额外的属性。

  • 在 EF 6.1 中不再如此。看我的回答。 (4认同)