Прочитайте значение PropertyInfo ссылочной сущности, используя EF4 - PullRequest
0 голосов
/ 27 января 2012

Я хотел бы динамически читать значения PropertyInfos объектов EntityObjects, с которыми я сталкиваюсь при циклическом просмотре PropertyInfos родительского объекта (значения столбцов экземпляра ImageType, который связан с текущим экземпляром Image, fi) .

Тип основного объекта известен только во время выполнения, поэтому я ищу общий способ чтения значений PropertyInfo любого объекта сущности, на который есть ссылка.

Я могу перебирать PropertyInfos дочерней сущности, но когда я пытаюсь получить значение, я получаю TargetException: объект не соответствует целевому типу.

// loop through the main entity's properties
foreach (PropertyInfo pi in entityType.GetProperties())
{
    // if the main entity's property is an entity
    if (pi.PropertyType.BaseType == typeof(System.Data.Objects.DataClasses.EntityObject))
    {
        // loop through the sub entity's properties
        foreach(PropertyInfo mychildren in pi.PropertyType.GetProperties())     
        {   
            // the loop works fine but when i try to get a value I get a
            // TargetException: Object does not match target type.
            object test = mychildren.GetValue(pi, null);
        }
    }
}

Как я могу это сделать?

Редактировать :

Entity Framework 4.0, по-видимому, не позволяет динамически извлекать экземпляры связанных сущностей сущности. Но с EF 4.1 и выше вы можете, используя их имя класса в качестве строкового идентификатора. Поэтому я обновился до EF 4.2 и начал работать.

Причина, по которой я хотел этот код, состоит в том, чтобы использовать его в моей процедуре перевода DTO. Мои DTO могут иметь строковые свойства, которые соответствуют свойствам имен связанных объектов, и таким образом я могу получить к ним доступ без необходимости жесткого кодирования типов связанных объектов.

В EF 4.1 и более поздних версиях ObjectContext обернут классом с именем DbContext, который предоставляет навигационные свойства, с помощью которых можно получить экземпляры связанных объектов, используя строки. Чтобы динамически получить единственную связанную сущность, вы можете использовать:

dynamic refObject = Activator.CreateInstance (refObjectType);

refObject = context.Entry (currentObject) .Reference (refObjectType.Name) .CurrentValue;

Для тех, кто обновляет с 4.0: рекомендуемый способ работы с DbContext не с EntityObjects, а с POCO. Это можно сделать вручную или с помощью контекстного меню edmx.

Моя текущая реализация выглядит следующим образом:

// Loop through the propertyinfos of the dto's type
foreach (PropertyInfo pf in dtoType.GetProperties().Where(p => p.CanWrite))
{
    // Use the name of the dto property to get the corresponding property from the POCO's type. If it doesn't exist, pi will be null
    PropertyInfo pi = pocoType.GetProperty(pf.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

    if (pi != null)
    {
        // Check if the current propertyinfo of the POCO has a subproperty named Id
        // If this is the case we treat the propertyinfo as a referenced POCO
        if (pi.PropertyType.GetProperty("Id") != null)
        {
            // skip referenced POCOs if their data is not needed
            if (!includeRelated) continue;

            // Get the type of the referenced POCO
            Type refObjectType = pi.PropertyType;
            // Create an instance of the referenced POCO
            dynamic refObject = Activator.CreateInstance(refObjectType);

            // Create a type of GenericRepository<objectType>
            Type refObjectRepositoryType = typeof(GenericRepository<>).MakeGenericType(refObjectType);
            // Create an instance of GenericRepository<objectType>
            dynamic refObjectRepository = Activator.CreateInstance(refObjectRepositoryType);

            // Fill the dynamic POCO instance with the values of the referenced POCO instance
            refObject = refObjectRepository._context.Entry(poco).Reference(refObjectType.Name).CurrentValue;

            try
            {
                // Set the dto property with the name value of the referenced POCO instance
                // (i.e. dtoImage.ImageType = pocImage.ImageType.Name)
                pf.SetValue(dto, refObject.Name, null);
            }
            catch (RuntimeBinderException)
            {
                // this happens when the related entity is null, ie. in one to zero-or-one relationships
                continue;
            }

            continue;
        }

        // If the propertyinfo's propertytype does not have an Id property, just set the value of  
        // the dto property to that of the POCO's propertyinfo directly
        pf.SetValue(dto, pi.GetValue(poco, null), null);

    }
}

На данный момент этот код будет работать только для ссылочных объектов, которые имеют свойства Id и Name. Кроме того, при таком подходе может быть снижение производительности, поэтому я применил флаг includeRelated для переключения, запрашивать ли связанные объекты или нет.

1 Ответ

1 голос
/ 27 января 2012

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

using (var context = new MyContext())
{
    var cust = context.Customer.First();
    var custType = cust.CustomerType;

    var pi = typeof (Customer).GetProperty("CustomerType");
    var child = pi.PropertyType.GetProperty("CustomerTypeID");

    var res = child.GetValue(custType, null);
    // this returns value of Customer.CustomerTypeID
}
...