Подтвердить что ты не робот

Как настроить Entity Framework для автоматической настройки значений, полученных для определенных столбцов, сопоставленных полям char (N)?

Я работаю с сторонней базой данных, в которой все текстовые значения хранятся как char(n). Некоторые из этих текстовых значений являются первичными ключами, тогда как другие являются обычным для человека понятным текстом. Для последнего я хочу, чтобы полученные значения были автоматически обрезаны.

Я знаю, что могу добавить Trim ко всем моим запросам LINQ to Entities, но это грязно, ненадежно и ненадежно. Я хотел бы как-то настроить Entity Framework для автоматической подстройки значений, полученных из определенных столбцов.

Однако я не знаю, как это сделать. Я использую API API. Самое близкое, о чем я думал до сих пор, это создание дополнительных свойств для обертывания реальных свойств с помощью вызовов методов Trim, но это грязно и все еще не очень удобно. Я также предпочел бы, чтобы обрезка выполнялась в базе данных, а не в приложении.

4b9b3361

Ответ 1

Роуэн Миллер (менеджер программ для Entity Framework в Microsoft) недавно опубликовала хорошее решение для этого, которое использует Interceptors. По общему признанию, это справедливо только в 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);
            }
        }
    }
}

Rowan продолжает: "Теперь, когда у нас есть перехватчик, нам нужно сказать EF, чтобы он его использовал. Это лучше всего сделать с помощью Code-Based Configuration. Мы можем просто отбросить следующий класс в той же сборке/проекте, что и наш контекст и EF подберет его".

using System.Data.Entity;

namespace FixedLengthDemo
{
    public class MyConfiguration : DbConfiguration
    {
        public MyConfiguration()
        {
            AddInterceptor(new StringTrimmerInterceptor());
        }
    }
}

Ответ 2

Используйте свойства с полями поддержки вместо автоматических свойств на ваших объектах.

Добавьте "Trim()" в средство настройки свойств, например:

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

Я написал свой собственный генератор POCO, который просто делает это автоматически, но если у вас нет такого варианта, ReSharper может добавлять поля поддержки к автоматическим свойствам в виде двух нажатий клавиш. Просто сделайте это для строк, и вы можете сделать глобальный (в области файлов) поиск/замену для "= value;" на "= value.Trim();".

Ответ 3

Entity Framework не предоставляет перехватчиков, чтобы изменить способ составления SQL-инструкций, поэтому вы не можете сказать ему, что они извлекают и строят строковые поля из базы данных.

Можно было бы обрезать свойства строки в событии ObjectContext.ObjectMaterialized, но я думаю, что это сильно повлияло бы на производительность. Кроме того, для определенных свойств потребовалось бы много кода if-else или switch, как вы намереваетесь сделать. Но стоит попробовать, если вы хотите сделать это почти для всех свойств (кроме ключей, например).

В противном случае я бы пошел на дополнительные свойства.

Ответ 4

Я использовал подход, данный Стюартом Грасси, но сначала это не сработало, потому что тип столбца содержал только "char", "varchar" и т.д. Столбцы фактически "char (30)", "varchar (10)" и т.д. После того, как я изменил линию, которая следует за ней, она работала как шарм!

от: if (propertyArg != null && _typesToTrim.Contains(propertyArg.Property.TypeUsage.EdmType.Name))

чтобы: if (propertyArg != null && _typesToTrim.Any(t => propertyArg.Property.TypeUsage.EdmType.Name.Contains(t)))

Спасибо Stuart!