代码之家  ›  专栏  ›  技术社区  ›  Deadpool

通过反射和ef core检查实体的属性是否标记为isRequired()。

  •  2
  • Deadpool  · 技术社区  · 7 年前

    问题

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

    例子

    这个问题必须特别针对 string 属性,与大多数值类型一样,如果db属性允许 null 值,然后由ef core的scaffolding操作将其映射为可空类型。

    例如:可以为空的int映射为 int? ,而不可为空的映射为 int .

    如果我迭代映射实体的属性,为了检查我现在迭代的属性是否可以为空,我只需要检查 myproperty.PropertyType == typeof(int?) 但是……如果是 一串 类型?

    有没有办法检查它是否标记为 ISAdvices() 财产?

    我的代码到目前为止

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

    • objectInstance :从我必须更新的实体派生的代理,我(必须)以前找到它
    • 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();
    

    其中“query”是扩展名:

    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);
        //...
     }
    

    我想达到的目标

    //here it is where I would like to do the above mentioned check 评论的位置,我想检查是否(伪代码):

    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));
       }
    }
    
    2 回复  |  直到 7 年前
        1
  •  4
  •   Ivan Stoev    7 年前

    在ef core中实现这一点的正确方法不是使用反射,而是ef core提供的元数据。这意味着您的方法应该具有 DbContext (或至少 IModel 返回的 DbContext.Model 财产)。

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

    获取一个值,该值指示此属性是否可以包含空值。

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

    像这样:

    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 方法。

    获取映射给定实体类的实体,其中该类可能是从实际实体类型派生的代理。如果找不到具有给定clr类型的实体类型,或者实体类型具有定义导航,则返回null。

        2
  •  1
  •   Fabien Sartori    7 年前

    是的,你应该这样做

     [IsNotNullable]
        [IsPK]
        [IsIdentity]
        [SequenceNameAttribute("Id")]
        [Required]
        public Int32 Id
        {
            get
            {
                return _Id;
            }
            set
            {
                _Id = value;
            }
        }
    var t = typeof(YourClass);
    var pi = t.GetProperty("Id");
    var attr = (Required[])pi.GetCustomAttributes(typeof(Required), false);
    if (attr.Length > 0) {
        // Use attr[0], you'll need foreach on attr if MultiUse is true
    }