如何确定数据库中哪些字段指定为NOT NULL?

我的解决方案中有一个数据库优先,代码生成的EF数据项目。

我需要做的是确定我的模型中的哪些字段在数据库中被定义为NOT NULL (即必需)。 这对于值类型(整数,浮点数,小数等)并不困难,因为如果DB允许空值,则它们被EF代码生成器定义为可空类型。

但是,当字段是引用类型时,我无法弄清楚如何确定字段是否在数据库中定义为NULL / NOT NULL

这似乎是一个显而易见的问题,但我无法通过Google或其他方式找到解决方案。 使用EF模型时,如何在保存操作成功之前查询模型中是否需要填充哪些字段?

一种不同的方法

重新访问这个问题后,我想我会做一些进一步的研究。 首先,通过Visual Studio添加实体,在单步执行EF向导后,生成了一个.edmx文件。 我之前已多次访问此文件,并且我已更新并将表添加到此文件中。

今天,我决定在设计师中打开它并查看我的一些领域的一些属性。 果然,我的nvarchar NOT NULL字段上有一个名为Nullable的属性。

那么,我如何使用EF并获得Nullable属性设置为false的实体上的字段列表?

您可以从Entity Framework的元数据中获取此信息:

 var metadata = ((IObjectContextAdapter)db).ObjectContext.MetadataWorkspace; var tables = metadata.GetItemCollection(DataSpace.SSpace) .GetItems().Single() .BaseEntitySets .OfType() .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); } } 

(其中dbDbContext

这将为您提供如下输出:

 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 

我从Rowan Miller那里借了第一部分。

我不确定这是否是最好的方法,但我为DbContext类创建了一个扩展方法,它接受数据表的字符串名称,然后在sys表中查询此元信息。 具体来说,我创建了以下2个类和扩展方法。


TableSchema表

这是用于存储相关架构详细信息的高级表类:

 public class TableSchema { public string Database { get; internal set; } public string TableName { get; internal set; } public List 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(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"); } }