2015-09-24 12 views
1

Я хотел бы применить одно преобразование к большому числу столбцов в Entity Framework 5 без необходимости явно вводить их все. В качестве примера я хотел бы сделать следующие более 50 столбцов (конвертировать PascalCase в UNDERSCORE_CASE).Скопируйте сопоставление столбцов сущности для преобразования имени столбца

modelBuilder.Entity<Department>() 
      .Property(t => t.DepartmentName) 
      .HasColumnName("DEPARTMENT_NAME"); 

Я нашел Dapper.FluentMap, которая может обеспечить эту функцию, но она не появляется на работе при создании запроса.

Есть ли способ перебрать список свойств и указать имя столбца после шаблона? Справочно щеголеватый Transform перечислен как

public PropertyTransformConvention() 
{ 
    Properties() 
     .Configure(c => c.Transform(s => Regex.Replace(input: s, pattern: "([A-Z])([A-Z][a-z])|([a-z0-9])([A-Z])", replacement: "$1$3_$2$4"))); 
} 

EDIT: Это похоже на this question, но она не работает для меня. Возможно, у этого есть разные требования к EF5.

Используя ответ от @Hopeless, я попытался выполнить следующую модификацию, но синтаксис не совсем прав. Я новичок в EF, поэтому не знаю, как преобразовать старый синтаксис в новый.

modelBuilder.Entity<Job>() 
      .Map(m => 
{ 
    m.Properties<Job>(e => e.HasColumnName(name => RegEx.Replace(name, "(?<=.)(?=[A-Z])", "_").ToUpper())); 
}); 

ответ

1

Вы можете использовать Properties метод DbModelBuilder. Перевести паскаль шаблон, чтобы подчеркнуть рисунок легко, как это:

modelBuilder.Properties() 
      .Configure(e => e.HasColumnName(Regex.Replace(e.ClrPropertyInfo.Name, "(?<=.)(?=[A-Z])", "_").ToUpper()); 

Шаблон также может быть, как это (.)([A-Z]) и замена должна быть затем $1_$2.

Конечно, имя ввода должно иметь форму SomeThing. Вы также можете взять шаблон в Dapper (опубликованный в вашем вопросе), который более точно работает в некоторых других редких случаях (даже в том числе и в этом формате DDos (который будет преобразован в D_Dos). Дело здесь не в переводе в верхний регистр для вы

Edit:.

жаль, что в EF5, MODELBUILDER не Properties() метод Таким образом, для конкретного типа сущности, вы можете попробовать это:.

//in your OnModelCreating scope 
//names of navigation properties defined in Job should be passed 
//in TransformAllColumns method 
new CapsUnderscorePropertiesConfig<Job>(modelBuilder).TransformAllColumns(); 

//a helper class 
public class CapsUnderscorePropertiesConfig<T> where T : class 
{ 
    EntityTypeConfiguration<T> _entityConfig; 
    Dictionary<Type, MethodInfo> _propertyMethods = new Dictionary<Type,MethodInfo>(); 
    MethodInfo propertyForStruct; 
    MethodInfo propertyForNullableStruct; 
    public CapsUnderscorePropertiesConfig(DbModelBuilder modelBuilder) 
    { 
     _entityConfig = modelBuilder.Entity<T>();    
    } 
    void config(PropertyInfo pInfo) 
    { 
     var p = Expression.Parameter(typeof(T)); 
     var expType = typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(typeof(T), pInfo.PropertyType)); 
     MethodInfo mi; 
     _propertyMethods.TryGetValue(pInfo.PropertyType, out mi); 
     if (mi == null) 
     { 
      if (pInfo.PropertyType.IsValueType) 
      { 
       //find the Property method for struct type having argument matching Expression<Func<TEntityType, T?>> 
       //note the T? inside Func<...> (there is another overload but with T instead). 
       if (propertyForStruct == null) 
       { 
        foreach(var prop in _entityConfig.GetType().GetMethods().Where(m => m.Name == "Property" && m.IsGenericMethodDefinition) 
                .Select(e => new { genMethodDef = e, genMethod = e.MakeGenericMethod(pInfo.PropertyType) })){  
         //there should be just 2 generic Property<T> methods filtered inhere. 
         //One is for nullable struct and the other is for struct. 
         var secondFuncArgType = prop.genMethodDef.GetParameters()[0].ParameterType.GetGenericArguments()[0].GetGenericArguments()[1]; 
         if (secondFuncArgType.IsGenericType && secondFuncArgType.GetGenericTypeDefinition() == typeof(Nullable<>)) 
          propertyForNullableStruct = prop.genMethodDef; 
         else propertyForStruct = prop.genMethodDef; 
        } 
       } 
       mi = pInfo.PropertyType.IsGenericType && pInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? 
        propertyForNullableStruct.MakeGenericMethod(pInfo.PropertyType) : 
        propertyForStruct.MakeGenericMethod(pInfo.PropertyType); 
      } 
      else //possible property type is string, byte[] or geo type 
      { 
       mi = _entityConfig.GetType().GetMethods().Single(m => m.Name == "Property" && !m.IsGenericMethodDefinition 
                   && m.GetParameters()[0].ParameterType == expType); 
      } 
      _propertyMethods[pInfo.PropertyType] = mi; 
     } 
     var propConfig = mi.Invoke(_entityConfig, new object[] { Expression.Lambda(Expression.Property(p, pInfo.Name), p) }) as PrimitivePropertyConfiguration;    
     propConfig.HasColumnName(Regex.Replace(pInfo.Name, "(?<=.)(?=[A-Z])", "_").ToUpper()); 
    } 
    //at the time of configuring, the Metadataworkspace is not present 
    //So we cannot know which properties are navigation properties 
    //Those propertie can be excluded by passing their names in here 
    public void TransformAllColumns(params string[] excludedNavProperties) 
    { 
     foreach (var prop in typeof(T).GetProperties().Where(p => !excludedNavProperties.Contains(p.Name))) 
     { 
      config(prop); 
     } 
    } 
} 

N OTE: Приведенный выше код работает только для прямых свойств, если у вас есть некоторые сложные свойства (возвращающий ComplexType), тогда это не сработает. Технически вам нужно исключить все свойства (возвращающие ComplexType) из свойств объекта, а затем, если возможно, объединить свойства ComplexType с прямыми свойствами объекта, прежде чем перебирать все и настраивать каждый.

PS: Я не уверен, если Dapper.FluentMap поддерживает EF5, но из кода вы в курсе, это может быть столь же легко, как прилагая ToUpper() метод, как это:

public PropertyTransformConvention() 
{ 
    Properties() 
    .Configure(c => c.Transform(s => Regex.Replace(input: s, pattern: "([A-Z])([A-Z][a-z])|([a-z0-9])([A-Z])", replacement: "$1$3_$2$4").ToUpper())); 
} 

Я пробовал посетить домашнюю страницу Dapper.FluentMap и выглядит так, что у него есть классы на основе Convention (если это от EF, он поддерживается только с EF6).Поэтому я не уверен, работает ли код Dapper в EF5. Если это работает, вы должны попробовать код выше для удобства.

+0

Выглядит отлично, но modelBuilder не имеет метода Properties(). Я обновил вопрос, чтобы указать, как я попытался использовать ваш ответ, но синтаксис неверен. – McArthey

+0

Что касается вашего редактирования, это именно то, что у меня есть в вопросе. Проблема в том, что e.HasColumnName выдает ошибку, потому что это не метод типа Job. – McArthey

+0

@McArthey извините, похоже, что с EF5 работать нелегко. Технически вам нужно использовать Reflection для циклического переключения всех свойств объекта (за исключением навигационных свойств), а затем выбрать правильный метод 'Property' (который довольно сложный) 'EntityTypeConfiguration', тогда вам нужно создать' Expression' (как аргумент для 'Property') вручную из свойства Type и его Name ... Это совсем не просто. Может быть, есть и другой подход. Позвольте мне попытаться выяснить или бороться с этим. Даже когда я это сделаю, я уведомит вас, чтобы попробовать (не уверен, что он может работать). – Hopeless