web-dev-qa-db-ja.com

Entity Framework CoreのDbContextから列名と対応するデータベースタイプを取得する方法

このテーブルがあるとしましょう:

enter image description here

Entity Framework CoreでDbContextから列名とデータベースデータ型を取得するにはどうすればよいですか?

チップ

  1. Clg#という名前の列がEF Core Scaffoldツールによってclg1に変換されたため、現在のEF名ではなく実際の列名が必要

  2. もちろん、clrTypeではなくデータベースタイプが必要です。もちろん、クロスプラットフォームである必要があります。多分私はデータベースを変更するので、メソッドも機能する必要があります。

望ましい結果:

    <D.clg#, int>
    <D.clgname, nvarchar(50)>
    <D.city, nvarchar(50)>
    <D.pname, nvarchar(50)>

誰かが解決策を提供できますか?

10
HamedFathi

更新(EF Core 3.x):EF Core 3.0以降、メタデータAPIが再び変更されました-Relational()拡張機能が追加されました削除され、プロパティはGetおよびSet拡張メソッドに置き換えられたため、コードは次のようになります。

_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();
};
_

更新(EF Core 2.x):EF Core 2.0以降、状況が変更されたため、元の回答は適用されなくなりました。 EF Coreはデータベースタイプごとに個別のモデルを構築するようになりました。そのため、コードははるかに単純になり、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;
};
_

元の回答(EF Core 1.x):

関連するメタデータへのアクセスの取得は、EFに比べてEF Coreではるかに簡単です。_DbContext.Model_プロパティから開始して IModel を取得し、GetEntityTypesを使用するか、 FindEntityTypeを取得するには IEntityType 、次にGetPropertiesまたはFindPropertyを取得するには IProperty =など.

ただし、問題はEF Coreを使用すると、さまざまなターゲットデータベースでさまざまな設定を使用できることです。コンテキストで使用されている現在のデータベースに対応する属性を取得するには、 IRelationalDatabaseProviderServices にアクセスし、 AnnotationProvider を使用する必要があります=および TypeMapper 必要な情報を取得するためのプロパティ。

次に例を示します。

_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
               };
    }
}
_
28
Ivan Stoev

ここに到着したが、私のように.NET COREを使用していない人向け。これを試して:

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();
    }
}

多分冗長ですが、時間を節約できます。

アントニオ

0
antonio