Entity Framework | Сначала код - получить имя созданной таблицы - PullRequest
8 голосов
/ 10 мая 2011

Возможно ли это?Я знаю, что могу получить имя, когда я указал TableAttribute, но это должно быть возможно даже тогда, когда я позволю фреймворку управлять именем.

Заранее спасибо.

Ответы [ 4 ]

11 голосов
/ 20 декабря 2011

Я закончил с этим:

public static class DbContextExt
{
    public static string GetTableName<T>(this DbContext context) where T : class
    {
        var type = typeof(T);
        var entityName = (context as System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext.CreateObjectSet<T>().EntitySet.Name;
        var tableAttribute = type.GetCustomAttributes(false).OfType<System.ComponentModel.DataAnnotations.Schema.TableAttribute>().FirstOrDefault();

        return tableAttribute == null ? entityName : tableAttribute.Name;
    }
}

Это гибрид двух ответов здесь: Имя таблицы DBset .

4 голосов
/ 01 августа 2014

Правильный способ сделать это - использовать метод GetTableName со следующей страницы: http://romiller.com/2014/04/08/ef6-1-mapping-between-types-tables/

Сюда входит поддержка мета-тега и изменений в конструкторе моделей .ToTable().Примеры на этой странице в основном возвращают имя свойства DbSet, которое не обязательно является именем таблицы в базе данных.

Например, если у вас было:

DbSet<Config> Settings { get; set; }

Код на этой страницебудет возвращать «Настройки» для имени таблицы, когда фактическое имя таблицы БД - «Конфиги».И у вас возникли бы те же проблемы, если бы вы использовали:

modelBuilder.Entity<Config>().ToTable("UserSettings")

Использование кода в приведенной ссылке облегчает все эти проблемы.Здесь это написано как расширение:

public static class DbContextExtensions
{
    public static string GetTableName<T>(this DbContext context) where T : class
    {
        var type = typeof(T);
        var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;

        // Get the part of the model that contains info about the actual CLR types
        var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace));

        // Get the entity type from the model that maps to the CLR type
        var entityType = metadata
                .GetItems<EntityType>(DataSpace.OSpace)
                .Single(e => objectItemCollection.GetClrType(e) == type);

        // Get the entity set that uses this entity type
        var entitySet = metadata
            .GetItems<EntityContainer>(DataSpace.CSpace)
            .Single()
            .EntitySets
            .Single(s => s.ElementType.Name == entityType.Name);

        // Find the mapping between conceptual and storage model for this entity set
        var mapping = metadata.GetItems<EntityContainerMapping>(DataSpace.CSSpace)
                .Single()
                .EntitySetMappings
                .Single(s => s.EntitySet == entitySet);

        // Find the storage entity set (table) that the entity is mapped
        var table = mapping
            .EntityTypeMappings.Single()
            .Fragments.Single()
            .StoreEntitySet;

        // Return the table name from the storage entity set
        return (string)table.MetadataProperties["Table"].Value ?? table.Name;
    }
}
2 голосов
/ 10 мая 2011

Если вы не используете TableAttribute или свободный API для определения имени таблицы, имя будет выведено из имени свойства DbSet в контексте. Единственное, что может изменить имя в таком случае, это соглашение о множественном числе, которое используется по умолчанию.

Так что если у вас есть:

public class Context : DbContext
{
    public DbSet<User> Users { get; set; }
}

Таблица должна называться Users.

1 голос
/ 16 февраля 2012

Это должно обрабатывать таблицу на тип и наследование таблицы на иерархию.

См: http://weblogs.asp.net/manavi/archive/2010/12/24/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph.aspx

Хитрость заключается в том, чтобы обходить дерево наследования до тех пор, пока вы не найдете переопределенный атрибут Table или необъектный базовый тип. Это может привести к сбою, если возможно наследовать от класса, который не сопоставлен с таблицей ... в чем я не уверен. Если вы можете сделать [NotMapped] для класса, то нам просто нужно изменить метод GetTableDefType, чтобы в этом случае один раз идти назад.

   private static Type GetTableDefType(this Type t, out TableAttribute attr) {
        attr = null;
        if (t == typeof(Object)) { throw new ArgumentException(); }
        var tType = t;
        while (true) {               
            attr = tType.GetCustomAttributes(false).OfType<TableAttribute>().FirstOrDefault();
            if (attr != null) { return tType; }

            if (tType.BaseType == null || tType.BaseType == typeof(Object)) { return tType; }
            tType = tType.BaseType;
        }
    }
    public static string GetTableName(this DbContext context, Type type)  {
        TableAttribute testAttr = null;
        var baseType = type.GetTableDefType(out testAttr);

        if (testAttr != null) { return testAttr.TableName; }

        var propBinding = BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty;
        var objectContext = context.GetType().GetInterface("System.Data.Entity.Infrastructure.IObjectContextAdapter").GetProperty("ObjectContext", propBinding).GetValue(context, null);
        var objectSet = objectContext.GetType().GetMethod("CreateObjectSet", new Type[0]).MakeGenericMethod(baseType).Invoke(objectContext, null);
        return ((EntitySet)objectSet.GetType().GetProperty("EntitySet", propBinding).GetValue(objectSet, null)).Name;
    }
...