在 EF7(核心)OnModelCreating 中使用自定义属性
Posted
技术标签:
【中文标题】在 EF7(核心)OnModelCreating 中使用自定义属性【英文标题】:Using a custom attribute in EF7 (core) OnModelCreating 【发布时间】:2017-05-30 14:27:24 【问题描述】:我有一个 DefaultAttribute
定义如下:
[AttributeUsage(AttributeTargets.Property)]
public class DefaultAttribute : Attribute
/// <summary>
/// Specifies this property has a default value upon creation.
/// </summary>
/// <param name="defaultValue">The default value of the property.</param>
/// <param name="useAsLiteral">Set to true if the value is <em>not</em> quoted in the DDL.</param>
public DefaultAttribute(object defaultValue, bool useAsLiteral = false)
DefaultValue = defaultValue;
UseAsLiteral = useAsLiteral;
public object DefaultValue get; private set;
/// <summary>
/// True if the default value is not quoted in the DDL
/// </summary>
public bool UseAsLiteral get; private set;
我用这个属性装饰了我的几个实体,如下所示:
public class MyEntity
. . . (other properties) . . .
[StringLength(200)]
[Required]
[Default("My Default Description!")]
public string Description get; set;
然后,在我的数据库上下文中的 OnModelCreating 方法中,我编写了以下代码:
//examine custom annotations for shaping the schema in the database.
foreach (var entityType in builder.Model.GetEntityTypes())
foreach (var property in entityType.GetProperties())
var annotations = property.GetAnnotations();
// evaluate default values
var defaultAnnotation = annotations.FirstOrDefault(x => x.Name == typeof(DefaultAttribute).FullName);
if (defaultAnnotation != null)
var defaultValue = defaultAnnotation.Value as DefaultAttribute;
if (defaultValue == null) continue;
if (defaultValue.UseAsLiteral)
property.Npgsql().DefaultValueSql = defaultValue.DefaultValue.ToString();
else
property.Npgsql().DefaultValue = defaultValue.DefaultValue;
我的期望是,在添加迁移(以及后续的数据库更新)时,会有一个默认值“我的默认描述!”对于MyEntity
的Description
列...但是,情况并非如此。
我没有收到任何错误,但它并没有像我想象的那样做,并且使用断点进入 OnModelCreating
也莫名其妙地难以做到。
我这样做正确吗?它只是不起作用吗? EF7 不支持它吗?还是我的 PostgreSQL 实现不支持它?任何见解将不胜感激。
更新 使用@IvanStoev 的回答,我能够让它与一些小的修改一起工作(.NET Core 中的反射与传统的有点不同):
//examine custom annotations for shaping the schema in the database.
foreach (var entityType in builder.Model.GetEntityTypes())
foreach (var property in entityType.GetProperties())
var memberInfo = property.PropertyInfo ?? (MemberInfo)property.FieldInfo;
var defaultValue = memberInfo?.GetCustomAttribute<DefaultAttribute>();
if (defaultValue == null) continue;
if (defaultValue.UseAsLiteral)
property.Npgsql().DefaultValueSql = defaultValue.DefaultValue.ToString();
else
property.Npgsql().DefaultValue = defaultValue.DefaultValue;
这就像一个冠军。
【问题讨论】:
【参考方案1】:EF Core 对您的自定义属性一无所知,因此无法发现它并将其作为注释公开(通常是不同的东西,不一定与属性相关联)。
您必须手动从PropertyInfo
或FieldInfo
中提取属性:
foreach (var entityType in builder.Model.GetEntityTypes())
foreach (var property in entityType.GetProperties())
var memberInfo = property.PropertyInfo ?? (MemberInfo)property.FieldInfo;
if (memberInfo == null) continue;
var defaultValue = Attribute.GetCustomAttribute(memberInfo, typeof(DefaultAttribute)) as DefaultAttribute;
if (defaultValue == null) continue;
if (defaultValue.UseAsLiteral)
property.Npgsql().DefaultValueSql = defaultValue.DefaultValue.ToString();
else
property.Npgsql().DefaultValue = defaultValue.DefaultValue;
【讨论】:
请注意,没有真正的理由要这样做.Npgsql()
- 这是为了在针对多个数据库时仅为 Npgsql 设置默认值。在大多数情况下,你应该简单地做property.HasDefaultValue(...)
(见docs.microsoft.com/en-us/ef/core/modeling/relational/…)以上是关于在 EF7(核心)OnModelCreating 中使用自定义属性的主要内容,如果未能解决你的问题,请参考以下文章
在 OnModelCreating 中撤消 HasIndex
在依赖注入中使用 Entity Framework Core DbContext 时不调用 OnModelCreating
如何在 EntityFramework Core 中使用部分类和部分 OnModelCreating 方法扩展 DbContext
以下方法或属性 [ Entity Framework Core ] [ OnModelCreating ] 之间的调用不明确