I'm not sure if this is the best approach but I created an extension method for the DbContext
class that takes a string name of a data table and then queries the sys
tables for this meta information. Specifically, I created the following 2 classes and extension method.
TableSchema
This is the high-level, table class used to store pertinent schema details:
public class TableSchema
{
public string Database { get; internal set; }
public string TableName { get; internal set; }
public List<ColumnSchema> Columns { get; internal set; }
}
ColumnSchema
Much like TableSchema, this is the class which will contain all schema related details for each column.
public class ColumnSchema
{
public string ColumnName { get; internal set; }
public int ColumnPosition { get; internal set; }
public string Collation { get; internal set; }
public string TypeName { get; internal set; }
public short Size { get; internal set; }
public byte Precision { get; internal set; }
public byte Scale { get; internal set; }
internal int _PK { get; set; }
public bool IsIdentity { get; internal set; }
public bool IsNullable { get; internal set; }
public bool IsPrimaryKey
{
get { return _PK == 1; }
}
}
The Extension method (GetDbTableSchema)
This method extends the DbContext
class. This makes acquiring the underlying table details as simple as passing a name into a method, right off of your instantiated context.
public static class DbContextExtensions
{
public static TableSchema GetDbTableSchema(this DbContext ctx, string tableName)
{
string qry = string.Format(
@"SELECT * FROM (SELECT DISTINCT
c.name AS ColumnName,
c.column_id AS ColumnPosition,
ty.name AS TypeName,
c.max_length AS Size,
c.precision AS Precision,
c.scale AS Scale,
CASE WHEN ic.column_id IS NOT NULL THEN 1 ELSE 0 END AS [_PK],
c.is_identity AS [IsIdentity],
c.is_nullable AS [IsNullable]
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
INNER JOIN sys.types ty ON c.system_type_id = ty.system_type_id
LEFT OUTER JOIN sys.indexes i ON c.object_id = i.object_id AND i.is_primary_key = 1
LEFT OUTER JOIN sys.index_columns ic ON i.object_id = ic.object_id
AND i.index_id = ic.index_id
AND c.column_id = ic.column_id
WHERE t.name = '{0}') t
ORDER BY _PK DESC, ColumnPosition", tableName);", tableName);
return new TableSchema
{
Columns = ctx.Database.SqlQuery<ColumnSchema>(qry).ToList(),
Database = ctx.Database.Connection.Database,
TableName = tableName
};
}
}
Usage is very simple. Assuming you have the name of the data table, pass it into your context.
using (var ctx = new MyEntityContext()
{
TableSchema ts = ctx.GetDbTableSchema("MyTable");
foreach (ColumnSchema cs in ts.Columns)
{
Debug.WriteLine("Column: {0}, {1}", cs.ColumnName, cs.IsNullable ? "NULL" : "NOT NULL");
}
}