Проверьте, помечено ли свойство сущности как IsRequired () с помощью отражений и EF Core. - PullRequest
0 голосов
/ 20 ноября 2018

ВОПРОС

Если у меня есть массив свойств определенной сущности, и я перебираю их, есть ли способ проверить, есть ли свойство отраженного типато, что я повторяю в каждом цикле, настроено как .IsRequired() на соответствующем объекте?

ПРИМЕР

Этот вопрос должен быть предназначен специально для string свойства, как и в большинстве типов значений, если свойство db допускает значения null, то оно сопоставляется операцией Scaffolding EF Core как обнуляемый тип.

EG: обнуляемое int отображается как int?в то время как ненулевое значение отображается как int.

Если я перебираю свойства этого сопоставленного объекта, чтобы проверить, является ли это свойство, которое я перебираю сейчас, обнуляемым, мне просто нужно проверить, является ли myproperty.PropertyType == typeof(int?) но ... что в случае типа string?

Можно ли проверить, помечено ли оно как свойство .IsRequired()?

МОЙ КОД ТАКFAR

В моем коде у меня есть следующая функция, котораяПредполагается, что ch получает в виде параметров:

  • 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();

Где «Запрос» является расширением:

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 ]

0 голосов
/ 20 ноября 2018

Правильный способ сделать это в EF Core - не использовать отражение, а EF Core предоставил метаданные.Это означает, что ваш метод должен иметь доступ (получать в качестве аргумента) к DbContext (или по крайней мере IModel , возвращаемому свойством DbContext.Model ).

После того, как вы получитетаким образом, вы можете использовать метод FindEntityType , чтобы получить IEntityType , содержащий связанные метаданные с классом сущности, а затем некоторые из методов FindProperty перегружаются, чтобы получить IProperty , содержащий метаданные, связанные с этим свойством, и, наконец, проверьте свойство IsNullable :

Получает значение, указывающее, может ли это свойство содержать значение 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 .

Получает объект, которыйсопоставляет данный класс сущности, где класс может быть прокси, полученным из фактического типа сущности.Возвращает null, если не найден тип сущности с данным типом CLR или тип сущности имеет определяющую навигацию.

0 голосов
/ 20 ноября 2018

Да, вы должны сделать это

 [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
}
...