Получить TableName объекта при использовании Fluent API

Я использую свободный API для изменения имен таблиц для моих сущностей, таких как:

 public class TestMap : EntityTypeConfiguration<Domain.Test>
    {
        public TestMap()
        {
            ToTable("Test");
        }
    }

Теперь позже в моем DbContext Я хочу найти имя таблицы для типа, но когда я смотрю внутрь MetadataWorkspace Я понимаю, я не могу найти тип Domain.Test, Я могу найти таблицу "Тесты", но я не могу сопоставить их, если у меня нет жесткого кода. Итак, мой вопрос, как я могу найти имя типа внутри MetadataWorkspace,

Код, который я использую, чтобы попытаться найти тип Domain.Test:

     ObjectContext octx = (context as IObjectContextAdapter).ObjectContext; ;
                var es = octx.MetadataWorkspace
                                .GetItems<EntityContainer>(DataSpace.SSpace)
                                .SelectMany(c => c.BaseEntitySets);

Отредактируйте простой пример моего кода для людей, чтобы проверить:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            var db = new Database();
            db.Set<Test>().Add(new Test {Name = "test"});
            var amount = db.SaveChanges();
        }

        public abstract class AbstractTest
        {
            public int Id { get; set; }
        }

        public class Test : AbstractTest
        {
            public string Name { get; set; }
        }

        public class Database : DbContext
        {

            public Database() : base("Database")
            {
                this.Configuration.ProxyCreationEnabled = false;
                this.Configuration.LazyLoadingEnabled = false;
            }

            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);

                // Remove pluralized tables
                modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
                modelBuilder.Conventions.Remove<PluralizingEntitySetNameConvention>();

                // Add all configurations within the current assembly.
                modelBuilder.Configurations.AddFromAssembly(typeof(Database).Assembly);
            }

             public override int SaveChanges()
             {
                 foreach (DbEntityEntry ent in ChangeTracker.Entries())
                 {
                     Type entityType = ent.Entity.GetType();

                     var names = Utility.GetTableNames(entityType, this);
                 }

                 return base.SaveChanges();
             }
        }

        public class AbstractTestMap : EntityTypeConfiguration<AbstractTest>
        {
            public AbstractTestMap()
            {
                this.HasKey(t => t.Id);
            }
        }

        public class TestMap : EntityTypeConfiguration<Test>
        {
            public TestMap()
            {
                this.Property(t => t.Name)
                    .HasMaxLength(200);

                ToTable("Tests");
            }
        }

        public static class Utility
        {
            public static IEnumerable<string> GetTableNames<TEntity>(DbContext context)
            {
                return GetTableNames(typeof(TEntity), context);
            }
            public static IEnumerable<string> GetTableNames(Type type, DbContext context)
            {
                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 sets (tables) that the entity is mapped
                var tables = mapping
                    .EntityTypeMappings.Single()
                    .Fragments;

                // Return the table name from the storage entity set
                return tables.Select(f => (string)f.StoreEntitySet.MetadataProperties["Table"].Value ?? f.StoreEntitySet.Name);
            }
        }
    }
}

1 ответ

Решение

Работа с этим объектом:

namespace YourNamespace.Domain{
    public class Test{
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

и эта карта:

namespace YourNamespace {
    public class TestMap : EntityTypeConfiguration<Domain.Test> {
        public TestMap() {
            ToTable("Test");
        }
    }
}

и этот контекст:

namespace YourNamespace {
    public class MyContext : DbContext{
        public DbSet<Test> Tests { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder){
            base.OnModelCreating(modelBuilder);
            modelBuilder.Configurations
                .AddFromAssembly(Assembly.GetExecutingAssembly());
        }
    }
}

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

public static class Utility {
    public static IEnumerable<string> GetTableNames<TEntity>(this DbContext context) {
        return GetTableNames(typeof(TEntity), context);
    }
    public static IEnumerable<string> GetTableNames(Type type, DbContext context) {
        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 sets (tables) that the entity is mapped
        var tables = mapping
            .EntityTypeMappings.Single()
            .Fragments;

        // Return the table name from the storage entity set
        return tables.Select(f => (string)f.StoreEntitySet.MetadataProperties["Table"].Value ?? f.StoreEntitySet.Name);
    }
}

Он вернет список всех имен таблиц. Для единственной табличной сущности - как в вашем случае - просто используйте tableNames.FirstOrDefault(t=> !string.IsNullOrWhiteSpace(t)), Также вы можете использовать его как служебный метод или метод расширения:

class Program {
    static void Main(string[] args) {
        // getting the list:
        using (var ctx = new MyContext()){
            var tableNames = ctx.GetTableNames<Test>();
            foreach (var tableName in tableNames)
                Console.WriteLine(tableName);
            Console.ReadLine();
        }

        // getting the single table-name - your case - 
        using (var ctx = new MyContext()){
            var tableNames = ctx.GetTableNames<Test>();
            var tableName = tableNames.FirstOrDefault(t=> !string.IsNullOrWhiteSpace(t))
            Console.WriteLine(tableName);
            Console.ReadLine();
        }
    }
}

Смотрите исходную статью здесь.

ОБНОВИТЬ:

На основе обновленного вопроса: у нас есть HierarchyMapping Вот; поэтому нам нужно изменить наш GetTableNames Способ поддержки наследования:

public static class Utility {
    public static IEnumerable<string> GetTableNames<TEntity>(this DbContext context) {
        return GetTableNames(typeof(TEntity), context);
    }
    public static IEnumerable<string> GetTableNames(Type type, DbContext context) {
        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 entitySetTop = metadata
            .GetItems<EntityContainer>(DataSpace.CSpace).SelectMany(s => s.EntitySets);
        //.Single()
        //.BaseEntitySets;

        var entitySet = entitySetTop
            .SingleOrDefault(s => s.ElementType.Name == entityType.Name);
        EntitySet entitySet2 = null;
        foreach (var s in entitySetTop) {
            if (s.ElementType.Name == entityType.Name) {
                entitySet2 = s;
                break;
            }
            var temp = entityType.BaseType;
            while (temp != null) {
                if (s.ElementType.Name == temp.Name) {
                    entitySet2 = s;
                    break;
                }
                temp = temp.BaseType;
            }
            if (entitySet2 != null)
                break;
        }
        entitySet = entitySet2;


        // 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 sets (tables) that the entity is mapped
        var tables = mapping
            .EntityTypeMappings.Where(f => {
                if (f.IsHierarchyMapping) {
                    return f.EntityTypes.Any(e => e.Name == entityType.Name);
                }
                return f.EntityType.Name == entityType.Name;
            }).SelectMany(t => t.Fragments); //.Single()
        //.Fragments;

        // Return the table name from the storage entity set
        return tables.Select(f => (string)f.StoreEntitySet.MetadataProperties["Table"].Value ?? f.StoreEntitySet.Name);
    }
}
Другие вопросы по тегам