Как справиться с многокритериальными запросами в 3-уровневой архитектуре

Предполагается базовое 3-уровневое приложение (UI-Service-Data Access) с полной абстракцией уровня доступа к данным (SQL, Xml ...)

Приложения пользовательского интерфейса состоят из Datagrids с фильтрами по нескольким критериям, находят и т. Д.

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

Обратите внимание, что уровень пользовательского интерфейса не знает, как работает DAL.

7 ответов

Вот для чего нужен DTO.

Мне нравится использовать Query-By-Example для этого. Здесь вы можете передать фактический пример DTO, и любые не имеющие значения по умолчанию поля представляют критерии для запроса.

например

CustomerDTO example = new CustomerDTO();
example.lastName = "jones";
AddressDTO exAddr = new AddressDTO();
exAddr.city = "Boston";
example.addresses.add(exAddr);

var customers = svc.GetCustomersLike(example);

Это может быть использовано на сервисном уровне или на более высоком уровне.

Я использую дозвуковой и передаю коллекцию предложений where в метод сервиса

Вы можете создать объект, который содержит что-то вроде KeyValuePair для каждого критерия, по которому вы хотите фильтровать. Ваш DAL может затем построить условие where из этого..

Как это:

class MultiCriteriaFiltering
{
    List<FilterCriteria> Criterias;

    // this method just sits here for simplicity - it should be in your DAL, not the DTO
    string BuildWhereCondition()
    {
        StringBuilder condition = new StringBuilder();
        condition.Append("WHERE (1=1) "
        foreach (FilterCriteria criteria in Criterias)
        {
            condition.Append(" AND ").Append(criteria.FieldName).Append(" = ");
            condition.Append("'").Append(criteria.FilterValue).Append("'");
        }
        return condition.ToString();
    }
}

class FilterCriteria
{
    string FieldName { get; set; }
    object FilterValue  { get; set; }
}

Вы можете легко расширить это, например, добавить поле "оператор" в класс FilterCriteria, чтобы предоставить больше возможностей фильтрации, чем просто точное совпадение.

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

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

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

Ознакомьтесь с учебным пособием Роба. Он использует модель, которая передается из DAL, через уровень Service и даже используется в уровне UI. Это нормально и не нарушает ваших требований, когда пользовательский интерфейс не может знать, как реализован DAL. Вы можете легко переместить свою модель домена в другой проект VS, если вы хотите, чтобы сторонние приложения получили доступ к вашему сервисному уровню и не знали, как работает DAL.

Этот ответ содержит некоторые подробности о том, как абстрагировать функции LinqToSql от более высоких уровней. Возможно, вы захотите сделать это, если, как и я, вам нравятся функции отложенного выполнения LinqToSql, но вы не хотите, чтобы ваше приложение зависело от LinqToSql в качестве поставщика данных.

Есть несколько способов сделать это, я использовал сочетание критериев API и объектов запросов. Например, если у вас есть коллекция Persons, которую вы хотите запросить:

1) API критериев более гибкого пути: GetPerson(запрос IList)

public class Criteria
{
 Object Property; // (Domain property, not DB)// (String Or Lambda) Age, Father.Age, Friends, etc
 Object Operator; //(Enum or String)(Eq, Gr, Between,Contains, StartWith, Whatever...)
 Object Value; // (most likely Object, or use generics Criteria<T>), (Guid, int[], Person, any type).
}

2) Сильно описанный объект запроса:

public class PersonQuery
{
 Guid? Id;
 GenderEnum? Gender;
 Int32? Age;
 Int32? AgeMin;
 Int32? AgeMax;
 String Name;
 String NameContains;
 Person FatherIs;
 Person MotherIs;
 //...
}

Используйте Nullable<> для типов значений и присвойте значение Null, чтобы указать, что параметр не требуется.

У каждого метода есть положительные и отрицательные стороны.

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