Итерация через свойства и значения объекта, возвращаемого с помощью запроса linq на модели домена

У меня есть пользовательский объект в реляционной базе данных, который я сопоставил с CLR с помощью модели домена. Поэтому, используя следующий оператор, я могу вытащить сущность из моей базы данных в память через запрос LINQ в модели домена, например:

var inspection = (from i in dbContext.New_testinspectionExtensionBases
              where i.New_testinspectionId == currentInspection   
              select i).First();                         

В этом объекте есть свойства/поля, к которым мне нужен доступ, мне нужно определить имя свойства/поля, а также его значение. Я хочу пропустить эти элементы в памяти и записать их имена и значения на консоль.

Я попытался использовать этот подход, но не смог понять, как исправить синтаксис (я не уверен, что GetProperties - правильный метод для использования, GetFields почему-то ничего не возвращал, поэтому я предположил, что это так идти), но это не имеет большого значения, поскольку все, что мне нужно, - это доступ на чтение к значению;

var inspectionReportFields = inspection.GetType().GetProperties(); 
// I called this inspectionReportfields because the entity properties correspond to 
// form/report fields I'm generating from this data.

foreach (var reportField in inspectionReportFields)
{
    var value = reportField.GetValue();
    Console.WriteLine(reportField.Name);
    Console.WriteLine(value);
}

Есть ли более простой способ получить значение свойства/поля при использовании такой модели домена, как EF или openaccess? Если нет, я собираюсь сделать это правильно? И, наконец, как это сделать, как я могу исправить синтаксис в объявлении переменной значения?

Вот некоторые примеры полей/свойств из кода, сгенерированного моделью домена, для справки;

    private int? _new_systemGauges;
    public virtual int? New_systemGauges 
    { 
        get
        {
            return this._new_systemGauges;
        }
        set
        {
            this._new_systemGauges = value;
        }
    }

    private int? _new_systemAlarm ;
    public virtual int? New_systemAlarm 
    { 
        get
        {
            return this._new_systemAlarm;
        }
        set
        {
            this._new_systemAlarm = value;
        }
    }

Ответ 1

Я предполагаю, что вы пытаетесь определить универсальный способ "сбрасывать" объект, ничего не зная о его структуре. Если это так, то вы делаете все правильно. Вы используете отражение (GetType() и связанные методы класса Type) для проверки объекта и возврата его информации.

Причина GetFields() ничего не вернула, так это то, что вы, скорее всего, не указали правильные флаги привязки. В частности, если вы вызываете перегрузку, которая не принимает никаких параметров, вы возвращаете только теги public; если вам нужны частные поля, вам нужно их специально спросить.

В вашем случае GetFields(BindingFlags.NonPublic) вернет вам поля _new_systemGauges и _new_systemAlarm, а GetProperties() вернет вам свойства New_systemAlarm и New_systemAlarm.

Другим ключевым элементом, который вы пропустили, является то, что возвращаемые вами данные - это метаданные типа; он определяет структуру class, а не какой-либо конкретный экземпляр. Если вы хотите знать, что значение свойства для конкретного экземпляра, вы должны спросить об этом:

foreach (var prop in obj.GetType().GetProperties())
{
  Console.WriteLine("{0} = {1}", prop.Name, prop.GetValue(obj, null));
}

У вас есть один из элементов PropertyInfo из метаданных типа, вы можете запросить это значение свойства в любом экземпляре этого типа. Он не должен быть тем же самым экземпляром, который вы изначально использовали. Например:

var objs = somelist.Where(x => x.Id == 1);
foreach (var prop in objs.First().GetType().GetProperties())
{
  int x = 0;
  foreach (var obj in objs)
  {        
    if (prop.PropertyType.Name.Equals("Int32"))
    {
      int val = (int)prop.GetValue(obj, null);
      Console.WriteLine("Obj #{0}: {1} = 0x{2:x8}", x++, prop.Name, val);
    }
    else if (prop.PropertyType.Name.Equals("Decimal"))
    {
      int val = (decimal)prop.GetValue(obj, null);
      Console.WriteLine("Obj #{0}: {1} = {2:c2}", x++, prop.Name, val);
    }
    else
    {
      Console.WriteLine("Obj #{0}: {1} = '{2}'", x++, prop.Name, prop.GetValue(obj, null));
    }
  }
}

Технически вы должны проверить результат GetIndexParameters, чтобы узнать, проиндексировано ли свойство или нет; параметр null для GetValue на самом деле является массивом значений индекса.

Чтобы преобразовать возвращаемое значение, вы можете либо использовать приемы типа, либо если вы хотите быть более гибким, используйте методы класса Convert. Разница заключается, например, в том, что если у вас есть свойство short, GetValue() будет возвращать коробочное короткое число, которое вы не можете тогда typecast как int; вам нужно сначала распаковать его на short. Использование Convert.ToInt32() выполнит все необходимые шаги, чтобы получить значение int из любого свойства, которое можно конвертировать в целое число.

Преобразование между ссылочными типами проще, поскольку для этого можно просто использовать is и as; они работают так же, как вы ожидали бы с "отраженными" значениями свойств.

Ответ 2

GetProperties действительно правильный метод.

Чтобы избавиться от ошибки компилятора, измените код на это:

var value = reportField.GetValue(inspection, null);

Вам нужно передать экземпляр, из которого вы хотите получить значение, поскольку объект PropertyInfo не привязан к какому-либо конкретному экземпляру класса.


Пожалуйста, рассмотрите стандартные правила именования .NET.

Это приведет к следующему:

NewSystemAlarm вместо New_systemAlarm
NewSystemAlarm или _newSystemAlarm вместо _new_systemAlarm
NewTestInspectionExtensionBases вместо New_testinspectionExtensionBases
NewTestInspectionId вместо New_testinspectionId

Ответ 3

Если вы используете OpenAccess, у вас всегда есть полная информация о ваших классах моделей в вашем распоряжении. Информация, полученная от вашего сопоставления, означает, что вам не нужно отражать свои классы (без накладных расходов).

Просто просмотрите контекст контекста. Metadata.PersistentTypes для всех ваших картографических данных.