2013-05-07 2 views
1

Я занимаюсь созданием модели домена и хотел бы иметь класс BaseEntity с свойством «Id» (и некоторыми другими материалами отслеживания аудита). Свойство Id - это первичный ключ, и каждый объект Entity в моей модели домена наследует класс BaseEntity. Довольно простая вещь .....Измените имя столбца Identity Column для всех объектов

public class BaseEntity 
{ 
    [Key] 
    public int Id { get; set; } 

    public DateTime LastUpdate { get; set; } 
    public string LastUpdateBy { get; set; } 
} 
public class Location : BaseEntity 
{ 
    [Required] 
    public string Name { get; set; } 

    public string Description { get; set; } 
} 

Используя пример выше, я хотел бы, чтобы отобразить поле «Id» в колонку «LocationId». Я понимаю, что я могу использовать MODELBUILDER сделать это для каждого объекта в явном виде, делая что-то вроде этого:

modelBuilder.Entity<Location>().Property(s => s.Id).HasColumnName("LocationId"); 

Но я хотел бы сделать это для каждого объекта в моей модели домена, и это было бы некрасиво.

Я пробовал следующую битку отражения, но мне не повезло. По какой причине, компилятор «не может разрешить тип символа»:

foreach (var type in GetTypesInNamespace(Assembly.Load("Domain.Model"),"Domain.Model")) 
{ 
    modelBuilder.Entity<type>().Property(x=>x.Id)..... 
} 

Есть ли способ определить соглашение переопределения PrimaryKey по умолчанию соглашения о к карте моей собственности «Id» в собственность «ClassNameId» в базе данных ? Я использую Entity Framework 6.

+0

Есть ли причина, по которой вам необходимо использовать EF6 (который все еще находится в Alpha), а не EF5? – gunr2171

+0

Нет особых причин, нет. Это всего лишь новый проект, и я экспериментирую с EF6. Можете ли вы сделать то, что я пытаюсь сделать в EF5? – lafferrs

+0

Я бы предложил использовать EF5, потому что он стабильный. Однако вы должны прочитать [эту страницу] (http://entityframework.codeplex.com/wikipage?title=specs), чтобы убедиться, что то, что вы пытаетесь сделать, выполняется только EF6. – gunr2171

ответ

2

Вы должны взглянуть на Custom Code First Conventions. Для этого вам нужен EF6, но похоже, что вы уже используете его.
Чтобы дать вам обзор, взгляните на следующее соглашение, которое я использовал для преобразования имен PascalCase для подстановки имен. Он включает соглашение для свойств id ... Он также включает дополнительный префикс имени таблицы.

public class UnderscoreNamingConvention : IConfigurationConvention<PropertyInfo, PrimitivePropertyConfiguration>, 
              IConfigurationConvention<Type, ModelConfiguration> 
{ 
    public UnderscoreNamingConvention() 
    { 
     IdFieldName = "Id"; 
    } 

    public string TableNamePrefix { get; set; } 

    public string IdFieldName { get; set; } 

    public void Apply(PropertyInfo propertyInfo, Func<PrimitivePropertyConfiguration> configuration) 
    { 
     var columnName = propertyInfo.Name; 

     if (propertyInfo.Name == IdFieldName) 
      columnName = propertyInfo.ReflectedType.Name + IdFieldName; 

     configuration().ColumnName = ToUnderscore(columnName); 
    } 

    public void Apply(Type type, Func<ModelConfiguration> configuration) 
    { 
     var entityTypeConfiguration = configuration().Entity(type); 
     if (entityTypeConfiguration.IsTableNameConfigured) return; 

     var tableName = ToUnderscore(type.Name); 

     if (!string.IsNullOrEmpty(TableNamePrefix)) 
     { 
      tableName = string.Format("{0}_{1}", TableNamePrefix, tableName); 
     } 

     entityTypeConfiguration.ToTable(tableName); 
    } 

    public static string ToUnderscore(string value) 
    { 
     return Regex.Replace(value, "(\\B[A-Z])", "_$1").ToLowerInvariant(); 
    } 
} 

Вы можете использовать его как этот

modelBuilder.Conventions.Add(new UnderscoreNamingConvention { TableNamePrefix = "app" }); 

EDIT: В вашем случае метод Apply должно быть что-то вроде этого:

public void Apply(PropertyInfo propertyInfo, Func<PrimitivePropertyConfiguration> configuration) 
{ 
    if (propertyInfo.Name == "Id") 
    { 
     configuration().ColumnName = propertyInfo.ReflectedType.Name + "Id"; 
    } 
} 
+0

Спасибо! Это именно то, что я искал. – lafferrs

0

старта динамического подход, если НЕ используя пользовательские соглашения

modelBuilder.Entity<Location>().Property(s => s.Id).HasColumnName("LocationId"); 

Вы можете сделать это с помощью отражения от контекста. Псевдокоде как объяснение:

Reflect Context to get a list of POCO names 
For each POCO in a dbcontext. 
Map Property Id -> string PocoName+Id 

Вот расширения, которые я использую для этого типа решения.

// DBSet Types is the Generic Types POCO name used for a DBSet 
    public static List<string> GetModelTypes(this DbContext context) { 
     var propList = context.GetType().GetProperties(); 
     return GetDbSetTypes(propList); 
    } 

    // DBSet Types POCO types as IEnumerable List 
    public static IEnumerable<Type> GetDbSetPropertyList<T>() where T : DbContext { 
     return typeof (T).GetProperties().Where(p => p.PropertyType.GetTypeInfo() 
                 .Name.StartsWith("DbSet")) 
         .Select(propertyInfo => propertyInfo.PropertyType.GetGenericArguments()[0]).ToList(); 
    } 


    private static List<string> GetDbSetTypes(IEnumerable<PropertyInfo> propList) { 
     var modelTypeNames = propList.Where(p => p.PropertyType.GetTypeInfo().Name.StartsWith("DbSet")) 
            .Select(p => p.PropertyType.GenericTypeArguments[0].Name) 
            .ToList(); 
     return modelTypeNames; 
    } 

    private static List<string> GetDbSetNames(IEnumerable<PropertyInfo> propList) { 
     var modelNames = propList.Where(p => p.PropertyType.GetTypeInfo().Name.StartsWith("DbSet")) 
           .Select(p => p.Name) 
           .ToList(); 

     return modelNames; 
    } 

Однако вам все равно придется работать с динамической лямбдой сотрудника. Продолжить эту тему здесь: Dynamic lambda example with EF scenario

EDIT: Добавить ссылку на другой вопрос, что решения общих основных настроек классовый подход Abstract domain model base class when using EntityTypeConfiguration<T>

+0

Привет, Спасибо за ваш ответ. Я попробовал что-то вроде предложения, но проблема в том, что независимо от того, как я создаю список типов, я не могу использовать их в вызове 'modelBuilder.Entity () .Property()'. Кажется, что я не могу использовать отраженный тип в целом. Я просмотрел [эту статью stackoverflow] (http://stackoverflow.com/questions/955331/creating-a-generic-object-based-on-a-type-variable), но мы не можем этого сделать, потому что мы необходимо вызвать из объекта в общий тип, чтобы вызвать метод «Свойство()». – lafferrs

+0

Возможно с динамической лямбдой, расширения должны помочь отразить контекст. –

1

Попробуйте это в вашем классе DbContext ;

int - это CLR Тип полей моего основного ключа. Я хочу ссылаться на все ключи в коде как Id, но для ключей DBA требуются идентификаторы с префиксом имени сущности таблицы. Выше дает мне именно то, что я хочу в моей созданной базе данных.

Требуется Entity Framework 6.x.

0

Ответ Piggybacking на @ Monty0018, но это нужно немного обновить, если, как и я, вы используете Entity Framework 7 и/или SQLite.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
     try 
     { 
      _builder = modelBuilder; 
      var typeName = typeof(T).Name; 

      _builder 
       .Entity(typeof(T)) 
       .Property<int>("Id") 
       .ForSqliteHasColumnName(typeName + "Id"); 
     } 

     catch (Exception e) 
     { 
      throw e; 
     } 
}