Используйте DefaultIfEmpty, чтобы получить значения класса по умолчанию при использовании Union

Мне нужно вернуть набор MyClass на основе списка значений кортежа. Эти значения кортежа используются для получения правильного объекта из базы данных. Чтобы не вызывать дБ много раз, я пытаюсь использовать Union построить запрос, а затем получить все данные из базы данных только один раз, вызывая .ToList() метод. В этом случае, если в запросе нет результатов, мне нужно вернуть объект значения по умолчанию. Когда я применяю DefaultIfEmpty метод я получаю ошибку. Идея в том, если я получу List из 15 кортежей мне нужно вернуть 15 результатов, если результатов не было, они должны быть заполнены встроенным значением по умолчанию Class значение.

public ISet<MyClass> Post([FromBody] IList<Tuple<string, string>> codesToFilter)
{
    IEnumerable<MyClass> filteredObjectsByCodes = new List<MyClass>();

    foreach (Tuple<string, string> tupleElement in codesToFilter)
    {
        //Class built based on parameters to be returned if there are no records in db
        MyClass classDefaultValue = new MyClass(tupleElement.Item1,
            "A default property string",
            "Default text",
            tupleElement.Item2);

        var filteredObjects = (from entity in DatabaseContext.MyEntities
                               where (entity.Property1 == tupleElement.Item1 &&
                                   entity.Property4== tupleElement.Item2)
                               select new MyClass
                               (
                                   entity.Property1,
                                   entity.Property2,
                                   entity.Property3,
                                   entity.Property4
                               )
                              ).DefaultIfEmpty(classDefaultValue);

        filteredObjectsByCodes = filteredObjectsByCodes.Union(filteredObjects);
    }

    var filteredObjectsResult = new HashSet<MyClass>((filteredObjectsByCodes.ToList()));

    return filteredObjectsResult;
}

Любая идея о том, как сделать это оптимизированным способом?

2 ответа

Решение

Возможно, вы можете удалить DefaultIfEmpty и добавить недостающие MyClasses позже.

IEnumerable<MyClass> results  = filteredObjectsByCodes.ToList();

var missing = codesToFilter
    .Where(c => results.All(f => f.Property1 != c.Item1 && f.Property4 != c.Item2))
    .Select(c =>  new MyClass(tupleElement.Item1.. );

results = results.Union(missing);

return new HashSet<MyClass>(results);

Вызов AsEnumerable до звонка DefaultIfEmpty, Это операция, которую просто не имеет смысла выполнять в конце БД. Получите результаты из базы данных, и если она пуста, дайте приложению добавить элемент по умолчанию в последовательность.

Чтобы избежать выполнения Union на стороне приложения все, что вам нужно сделать, это применить AsEnumerable().DefaultIfEmpty(...) звоните после объединения различных запросов к БД. Там нет необходимости для DefaultIfEmpty выполняется перед агрегированием всех подзапросов.

Другие вопросы по тегам