c# - 通过反射和 EF Core 检查实体的属性是否被标记为 IsRequired()

标签 c# entity-framework-core system.reflection

问题

如果我有一个特定实体的属性数组并且我正在遍历它们,有什么方法可以检查我在每个循环中迭代的反射类型属性是否配置为 。 IsRequired() 在其对应的实体上?

示例

这个问题必须特别针对 string 属性,因为在大多数值类型中,如果 db 属性允许 null 值,则它由 EF Core 映射作为可空类型的脚手架操作。

例如:可为空的 int 映射为 int?,而不可为 null 的则映射为 int

如果我遍历该映射实体的属性,以检查我现在正在遍历的属性是否可为空,我只需要检查是否 myproperty.PropertyType == typeof(int?) 但是...如果是 string 类型怎么办?

有什么方法可以检查它是否被标记为 .IsRequired() 属性?

到目前为止我的代码

在我的代码中,我有以下函数,它应该作为参数接收:

  • objectInstance:派生 self 必须更新的实体的代理,我之前(必须)找到它
  • values:包含属性名称和我必须更新的属性的新值的字典。它可以填充所有属性,也可以只填充其中的一些属性。
  • properties:我之前通过反射找到的类的属性数组

这个函数应该遍历属性数组,并且对于每个属性,如果新值包含在字典中,则在类的实例上设置它的新值。

private static bool SetValues(Object objectInstance, Dictionary<string, object> values, PropertyInfo[] properties)
{
    bool edited = false;
    foreach (var item in values)
    {
        var temp = properties.Where(w => w.Name.ToLower() == item.Key.ToLower()).FirstOrDefault();
        if (temp != null)
        {
            edited = true;
            if (temp.PropertyType == typeof(string))
            {
                //here it is where I would like to do the above mentioned check
                temp.SetValue(objectInstance, Convert.ToString(item.Value));
            }
            if (temp.PropertyType == typeof(int) || temp.PropertyType == typeof(int?))
            {
                temp.SetValue(objectInstance, Convert.ToInt32(item.Value));
            }
            if (temp.PropertyType == typeof(long) || temp.PropertyType == typeof(long?))
            {
                temp.SetValue(objectInstance, Convert.ToInt64(item.Value));
            }
            if (temp.PropertyType == typeof(decimal) || temp.PropertyType == typeof(decimal?))
            {
                temp.SetValue(objectInstance, Convert.ToDecimal(item.Value));
            }
            if (temp.PropertyType == typeof(bool) || temp.PropertyType == typeof(bool?))
            {
                temp.SetValue(objectInstance, Convert.ToBoolean(item.Value));
            }
            if (temp.PropertyType == typeof(DateTime) || temp.PropertyType == typeof(DateTime?))
            {
                temp.SetValue(objectInstance, Convert.ToDateTime(item.Value));
            }
        }
    }
    return edited;
}

下面是我如何获得“objectInstance”:

var objectInstance = _context.Query(TableType).Where("Id = @0", rowKey).FirstOrDefault();

“查询”是一个扩展:

public static IQueryable Query(this DbContext context, Type entityType) =>
            (IQueryable)((IDbSetCache)context).GetOrAddSet(context.GetDependencies().SetSource, entityType);

还有...我用 IsRequired() 标记的实体属性的例子,以避免误解:

 public void Configure(EntityTypeBuilder<MyTable> builder)
 {
    //[a lot of properties above here...]
    builder.Property(e => e.Code)
                    .IsRequired()  //that's it!
                    .HasMaxLength(50)
                    .IsUnicode(false);
    //...
 }

我想要实现什么

//这里我想做上面提到的检查评论的位置,我想检查是否(伪代码):

if(temp.IsRequired())
{
   if(String.IsNullOrWhiteSpace(Convert.ToString(item.Value)))
   {
       temp.SetValue(objectInstance, "");
   }
   else
   {
       temp.SetValue(objectInstance, Convert.ToString(item.Value));
   }
}
else
{
   if(String.IsNullOrWhiteSpace(Convert.ToString(item.Value)))
   {
       temp.SetValue(objectInstance, null);
   }
   else
   {
       temp.SetValue(objectInstance, Convert.ToString(item.Value));
   }
}

最佳答案

在 EF Core 中执行此操作的正确方法不是使用反射,而是 EF Core 提供的元数据。这意味着您的方法应该可以访问(作为参数接收)DbContext(或至少由 IModel 属性返回的 DbContext.Model)。

一旦你有了它,你就可以使用 FindEntityType获取IEntityType的方法包含与实体类关联的元数据,然后是一些 FindProperty方法重载以获取 IProperty包含与该属性关联的元数据,最后检查 IsNullable属性:

Gets a value indicating whether this property can contain null.

它正确地考虑了数据类型、数据注释和流畅的配置。

像这样:

private static bool SetValues(DbContext db, Object objectInstance, 
    Dictionary<string, object> values, PropertyInfo[] properties)
{
    var entityType = db.Model.FindEntityType(objectInstance.GetType());
    bool edited = false;
    foreach (var item in values)
    {
        var property = entityType.FindProperty(item.Key);
        if (property != null)
        {
            var propertyType = property.ClrType;
            bool isRequired = !property.IsNullable;
            // do something ...     
        }
    }
}

这消除了需要 PropertyInfo[] properties 参数。

更新:为了使用代理类,而不是 FindEntityType 使用 FindRuntimeEntityType方法。

Gets the entity that maps the given entity class, where the class may be a proxy derived from the actual entity type. Returns null if no entity type with the given CLR type is found or the entity type has a defining navigation.

关于c# - 通过反射和 EF Core 检查实体的属性是否被标记为 IsRequired(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53390946/

相关文章:

c# - 通过 .net 反射仅获取 protected 成员

c# - 当我在 sql 查询中使用 go 语句时,Oledb 连接出现错误

c# - GDAX/Coinbase API Level3 订单簿 - 跳过消息

c# - EF 核心 : Create a SQL user-defined type from a C# class

entity-framework - 实体类型 'BookId' 上的属性 'Library' 具有临时值。显式设置永久值或确保数据库是

c# - Entity Framework : writing a common method to check exist

c# - Gridview DataSource 有行,但 GridView 没有

c# - db4o 问题...在 IIS 重置/容器超出范围后不返回对象

c# - 多个 DbSet<> 用于同一实体但具有不同的过滤器

c# - 在 .NET 4.5 TypeInfo.DeclaredMembers 上过滤掉私有(private)成员