Получить 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);
}
}