Supponiamo di avere questa tabella:
Come posso ottenere il nome della colonna e il tipo di dati del database da DbContext
in Entity Framework Core?
Suggerimenti
La colonna con nome clg # convertita in clg1 dallo strumento Scaffold EF Core, quindi ho bisogno del nome della colonna reale non del nome EF corrente
Ho bisogno del tipo di database, non di clrType, ovviamente deve essere multipiattaforma. Forse cambierò il database quindi anche il metodo deve funzionare.
Risultato desiderato:
<D.clg#, int>
<D.clgname, nvarchar(50)>
<D.city, nvarchar(50)>
<D.pname, nvarchar(50)>
Qualcuno può fornire una soluzione?
Aggiornamento (EF Core 3.x): a partire da EF Core 3.0, l'API dei metadati è stata nuovamente modificata: le estensioni Relational()
sono state rimosse e le proprietà sono state sostituite con i metodi di estensione Get
and Set
, quindi ora il codice è simile al seguente:
var entityType = dbContext.Model.FindEntityType(clrEntityType);
// Table info
var tableName = entityType.GetTableName();
var tableSchema = entityType.GetSchema();
// Column info
foreach (var property in entityType.GetProperties())
{
var columnName = property.GetColumnName();
var columnType = property.GetColumnType();
};
Aggiornamento (EF Core 2.x): a partire da EF Core 2.0, le cose sono cambiate, quindi la risposta originale non si applica più. Ora EF Core crea un modello separato per ciascun tipo di database, quindi il codice è molto più semplice e utilizza direttamente le estensioni Relational()
:
var entityType = dbContext.Model.FindEntityType(clrEntityType);
// Table info
var tableName = entityType.Relational().TableName;
var tableSchema = entityType.Relational().Schema;
// Column info
foreach (var property in entityType.GetProperties())
{
var columnName = property.Relational().ColumnName;
var columnType = property.Relational().ColumnType;
};
Risposta originale (EF Core 1.x):
Ottenere l'accesso ai metadati associati è molto più semplice in EF Core rispetto a EF: si parte dalla proprietà DbContext.Model
per ottenere IModel
, utilizzare GetEntityTypes
o FindEntityType
per ottenere IEntityType
, quindi GetProperties
o FindProperty
per ottenere IProperty
ecc.
Tuttavia, il problema è che EF Core consente di utilizzare impostazioni diverse per database di destinazione diversi. Per ottenere gli attributi corrispondenti al database corrente utilizzato dal contesto, è necessario ottenere l'accesso a IRelationalDatabaseProviderServices
e utilizzare le proprietà AnnotationProvider
e TypeMapper
per ottenere le informazioni necessarie.
Ecco un esempio:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Storage;
public class DbColumnInfo
{
public string Name;
public string Type;
}
public static class RelationalDbHelpers
{
public static IEnumerable<DbColumnInfo> GetDbColums(this DbContext dbContext, Type clrEntityType)
{
var dbServices = dbContext.GetService<IDbContextServices>();
var relationalDbServices = dbServices.DatabaseProviderServices as IRelationalDatabaseProviderServices;
var annotationProvider = relationalDbServices.AnnotationProvider;
var typeMapper = relationalDbServices.TypeMapper;
var entityType = dbContext.Model.FindEntityType(clrEntityType);
// Not needed here, just an example
var tableMap = annotationProvider.For(entityType);
var tableName = tableMap.TableName;
var tableSchema = tableMap.Schema;
return from property in entityType.GetProperties()
let columnMap = annotationProvider.For(property)
let columnTypeMap = typeMapper.FindMapping(property)
select new DbColumnInfo
{
Name = columnMap.ColumnName,
Type = columnTypeMap.StoreType
};
}
}
Per coloro che sono arrivati qui, ma non utilizzano .NET CORE, come me. prova questo:
public partial class MyDbContext : System.Data.Entity.DbContext
{
public string GetTableName(Type entityType)
{
var sql = Set(entityType).ToString();
var regex = new Regex(@"FROM \[dbo\]\.\[(?<table>.*)\] AS");
var match = regex.Match(sql);
return match.Groups["table"].Value;
}
public string[] GetColumnName(Type entityType)
{
var strs = new List<string>();
var sql = Set(entityType).ToString();
var regex = new Regex(@"\[Extent1\]\.\[(?<columnName>.*)\] AS");
var matches = regex.Matches(sql);
foreach (Match item in matches)
{
var name = item.Groups["columnName"].Value;
strs.Add(name);
}
return strs.ToArray();
}
}
forse ridondante, ma fa risparmiare tempo.
antonio