我的解决方案中有一个数据库优先,代码生成的EF数据项目。
我需要做的是确定我的模型中的哪些字段在数据库中定义为NOT NULL
(即必需)。这对于值类型(整数,浮点数,小数等)并不困难,因为如果DB允许空值,则它们被EF代码生成器定义为可空类型。
但是,当字段属于引用类型时,我无法弄清楚如何确定字段是否在数据库中定义为NULL
/ NOT NULL
。
这似乎是一个显而易见的问题,但我无法通过Google或其他方式找到解决方案。使用EF模型时,如何在保存操作成功之前查询模型中是否需要填充哪些字段?
一种不同的方法
重新访问此问题后,我想我会做进一步的研究。首先,通过Visual Studio添加实体,在单步执行EF向导后,生成了.edmx
文件。我之前已多次访问此文件,并且我已更新并将表添加到此文件中。
今天,我决定在设计师中打开它并查看我的某些领域的一些属性。果然,我的nvarchar NOT NULL
字段中有一个名为Nullable
的属性。
那么,我如何使用EF并获取Nullable
属性设置为false
的实体上的字段列表?
答案 0 :(得分:5)
You can get this information from Entity Framework's the meta data:
var metadata = ((IObjectContextAdapter)db).ObjectContext.MetadataWorkspace;
var tables = metadata.GetItemCollection(DataSpace.SSpace)
.GetItems<EntityContainer>().Single()
.BaseEntitySets
.OfType<EntitySet>()
.Where(s => !s.MetadataProperties.Contains("Type") || s.MetadataProperties["Type"].ToString() == "Tables");
foreach (var table in tables)
{
Console.WriteLine(string.Format("{0}.{1}", table.Schema, table.Name));
foreach (var member in table.ElementType.Members)
{
var column = string.Format(" {0}, Nullable: {1}",
member.Name,
((TypeUsage)member.MetadataProperties["TypeUsage"].Value).Facets["Nullable"].Value);
Console.WriteLine(column);
}
}
(where db
is a DbContext
)
This will give you an output like:
dbo.Category
CategoryId, Nullable: False
CategoryName, Nullable: False
Description, Nullable: True
RowVersion, Nullable: False
dbo.Product
ProductId, Nullable: False
ProductName, Nullable: False
QuantityPerUnit, Nullable: False
UnitPrice, Nullable: True
StartDate, Nullable: False
RowVersion, Nullable: False
Image, Nullable: True
dbo.CategoryProduct
CategoryID, Nullable: False
ProductID, Nullable: False
I borrowed the first part from Rowan Miller.
答案 1 :(得分:0)
我不确定这是否是最佳方法,但我为DbContext
类创建了一个扩展方法,该方法采用数据表的字符串名称,然后在sys
表中查询此元数据信息。具体来说,我创建了以下2个类和扩展方法。
<强> TableSchema表强>
这是用于存储相关架构详细信息的高级表类:
public class TableSchema
{
public string Database { get; internal set; }
public string TableName { get; internal set; }
public List<ColumnSchema> Columns { get; internal set; }
}
<强> ColumnSchema 强>
与TableSchema非常相似,这个类将包含每列的所有与架构相关的详细信息。
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; }
}
}
扩展方法(GetDbTableSchema)
此方法扩展了DbContext
类。这使得获取基础表详细信息就像将名称传递给方法一样简单,就在实例化的上下文之外。
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
};
}
}
用法非常简单。假设您拥有数据表的名称,请将其传递给您的上下文。
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");
}
}