Поиск иглы (объекта) в стоге сена (родительский объект) Entity Framework 4 - PullRequest
1 голос
/ 22 марта 2012

У меня есть проект Entity Framework 4, в котором создан некоторый код поиска методом "грубой силы", который я хотел бы сократить до более общих и более управляемых кусков.

Один из моих частичных классов, Runобъект, содержит свойства навигации (коллекции сущностей) для других объектов (Run.Nodes, Run.Arcs), а также скаляры (GUID, Version #) и особые свойства навигации (объекты Entity - Run.TimeRange).

Run.Nodes - это коллекция базовых классов NodeBase с производными классами NodeTypeA, NodeTypeB и NodeTypeC.

Использование Reflection:

    public EntityObject FindDiscriminant<T>(T needle) where T : EntityObject
    {
        Boolean test = false;
        Type sourceType = this.GetType();

        String needleString = needle.GetType().BaseType.Name.ToString();
        String needleStringLookup = typeDict.Where(o => o.Key == needleString).FirstOrDefault().Value;

        //If we don't match anything that means that the object itself is a base class, so we need to try again
        if (needleStringLookup == null)
        {
            needleString = needle.GetType().Name.ToString();
            needleStringLookup = typeDict.Where(o => o.Key == needleString).FirstOrDefault().Value;
        }

        var needleProperty = Type.GetType(sourceType.FullName).GetProperty(needleStringLookup);
        var runValue = needleProperty.GetValue(this, null);

        if (runValue.GetType().ToString().Contains("EntityCollection"))
        {
            foreach (var obj in (runValue as EntityCollection<T>).ToList())
            {
                test = (obj as T).Discriminant(needle);
                if (test == true)
                    return obj;
            }
        }
        else
        {
            test = (runValue as EntityObject).Discriminant(needle);
            if (test == true)
                return (T)runValue;
        }
        return null;
    }

Этот метод отлично работает для EntityCollections (кромеNodeBase).Если я попытаюсь найти узел NodeTypeC в Run.Nodes, runValue будет EntityCollection из 173 объектов NodeBase.Но когда я пытаюсь выполнить итерацию по нему (.ToList ()), я получаю эту ошибку:

System.ArgumentNullException was unhandled
Value cannot be null.
Parameter name: source

Мой обходной путь - проверить, что EntityCollection имеет тип NodeBase, и иметь оператор if дляобработайте его и замените EntityCollection) .ToList () на EntityCollection) .ToList ()

Есть предложения?


Обновление моего вопроса для всех, кто ищет это.Код сильно изменился, и теперь я использую Делегаты в качестве SearchActions, и у меня есть общая процедура FindSomething, которая использует эти делегаты вместо нескольких процедур поиска, каждая из которых использует свой собственный тип ввода.

Примечанияявляются:

  • Метод обнаружения для определения, является ли мой объект, который я потянул с отражением, EntityObject или EntityCollection

  • Я использую частный методперебрать коллекцию EntityCollection, которую я передаю из моей обычной процедуры FindSomething.Это учитывает сравнения базового класса

  • Имея закрытый метод для вызова, я избегаю необходимости использовать приведение к EntityCollection - это также уходит: (runValue as EntityCollection)as (obj as T)

  • Я создал динамический словарь объектов, когда создаю экземпляр нашего приложения, - я просматриваю нашу коллекцию объектов и объектов карты, а также свойства, которые нам интересны, поэтому я надеваюне нужно грубой силой проходить через весь объект каждый поиск

  • Я использую динамический вместо var - я люблю динамический!И я больше не выполняю преобразование перед выполнением поиска.

  • Функция рекурсивная - делегат SearchAction снова вызывается во время кода итерации в методе IterateThroughEntityCollection.

Хорошо?Плохой?Комментарии?Обратная связь?Это работает для меня, и это быстро.

Вот пересмотренный код:

private EntityObject FindSomething<T>(Run haystack, T needle, SearchAction<T> sa)
{
    //First, assume we haven't found anything
    Boolean test = false;

    //Next, go through all the objects in a run and see if we find anything
    //No need to go through Arcs, if the needle is a type of NodeBase, etc.

    Type oldRunElementProperty = TypeReference.RunElementDictionary.Where(o => o.Key == type).Single().Key;
    PropertyInfo runValuePropertyToChange = TypeReference.RunElementDictionary.Where(o => o.Key == type).Single().Value;
    dynamic runValue = runValuePropertyToChange.GetValue(haystack, null);

    //Check to see if we're dealing with an EntityCollection or an EntityObject.  If it is an EntityObject, we can set that value
    //directly.  If it is a collection, we need to use the generic method
    if (runValuePropertyToChange.PropertyType.IsGenericType && runValuePropertyToChange.PropertyType.GetGenericTypeDefinition() == typeof(EntityCollection<>))
    {
        EntityObject result = IterateThroughEntityCollection(runValue, needle, sa);
        if (result != null) return result;
    }
    else
    {
        test = sa(runValue, needle); if (test == true) return runValue;
    }
    return null;
}

Закрытый итератор EntityCollection.

    private EntityObject IterateThroughEntityCollection<T,U>(EntityCollection<T> haystack, U needle, SearchAction<U> sa) where T: EntityObject
    {
        Boolean test = false;
        foreach(dynamic obj in haystack)
        {
            test = sa(obj, needle); 
            if (test == true) return obj;
        }
        return null;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...