使用Fluent API

时间:2015-07-05 16:32:11

标签: c# entity-framework ef-fluent-api

我使用流畅的api来更改我的实体的表名称,如:

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

现在稍后在我的DbContext中,我想查找某个类型的表名,但当我查看MetadataWorkspace时,我发现我无法找到类型Domain.Test 。我能找到表格&#34; Tests&#34;但除非我硬编码,否则我无法匹配。所以我的问题是如何在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 个答案:

答案 0 :(得分: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();
        }
    }
}

请参阅源文章here

<强>更新

根据更新的问题:我们在这里有一个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);
    }
}