Ниже описаны основные возможности, предоставляемые LINQProvider.
В примерах ds
- это сервис данных, полученный следующим образом:
var ds = (SQLDataService)DataServiceProvider.DataService;
Поддерживаемые типы
Числа
Помимо численных атрибутов объекта в запросах допускается использовать константы, переменные, а так же функции от них. Все это будет вычислено. Например, запрос выдающий все объекты с атрибутом Длина, равным атрибуту Ширина + 10:
int Number1 = 8;
int Number2 = 2;
IQueryable<Кошка> queryList = ds.Query<Кошка>();
IQueryable<Кошка> query = from pn in queryList where pn.Длина == Number1 + Number2 + pn.Ширина select pn;
List<DataObject> data = query.Cast<DataObject>().ToList();
Поддерживаются не только целые числа при построении ограничений.
float length = 10.0f;
IQueryable<Улица> queryList = ds.Query<Улица>();
IQueryable<Улица> query = from pn in queryList where pn.Протяженность > length select pn;
List<DataObject> data = query.Cast<DataObject>().ToList();
Строки
Contains, StartsWith, EndsWith
Для работы со строками Linq-провайдер позволяет использовать методы Contains, а также варианты StartsWith, EndsWith с одним оператором. Использование других вариантов StartsWith и EndsWith вызовет исключение MethodSignatureException
.
Выбрать кошек, чьи клички содержат подстроку “ош”
List<Кошка> cat = ds.Query<Кошка>(Кошка.Views.КошкаE).Where(o => o.Кличка.Contains("ош")).ToList();
Regex
В LINQProvider есть минимальная поддержка Regex (основные ограничения связаны с тем, что шаблон для регулярного выражения переводится в шаблон поиска для конструкции like в sql).
List<Порода> objss = ds.Query<Порода>(Порода.Views.ПородаE).Where(x => Regex.IsMatch(x.Название, "12.*3")).ToList();
Допустимые для использования в регулярных выражениях конструкции: “.”, “.*”, “^”, “$”.
Дата/Время
Для наложения ограничений на даты можно использовать различные свойства DateTime
.
Linq-провайдер не поддерживает метод DateTime.AddDays
. При попытке ее использования будет брошено исключение NotImplementedException
.
Можно использовать числовые компоненты даты, такие как год, месяц, день в месяце, час минута, день недели. При этом дни недели преобразуются в числа как в C# в перечислении DayOfWeek
(0 – воскресение, 1 – понедельник .. 6 – суббота). Для этого в была добавлена функция DayOfWeekZeroBased в дополнение к старой DayOfWeek.
При попытке использования свойств Ticks, Second, Millisecond, DayOfYear будет брошено исключение MethodSignatureException
.
Выбрать переломы которые были раньше, чем сегодня:
List<Перелом> objss = ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Дата.Date < DateTime.Now.Date).ToList();
Применение AddYears
DateTime now = DateTime.Now;
List<Перелом> objss = ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Дата.AddYears(1) < now.Date).ToList();
Выбрать переломы, произошедшие в воскресение.
List<Перелом> objss = ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Дата.DayOfWeek == DayOfWeek.Sunday).ToList();
NullableDateTime
Чтобы произвести сравнение NullableDateTime
с DateTime
нужно привести их к одному типу вне Linq-запроса.
DateTime date = new DateTime(2012, 1, 1);
NullableDateTime nullableDate = new NullableDateTime { Value = date };
// ДатаВыдачи имеет тип NullableDateTime.
List<Кредит> objss = ds.Query<Кредит>(Кредит.Views.КредитE).Where(к => к.ДатаВыдачи < nullableDate).ToList();
Логический тип
Возможно использование не только выражений, но и их комбинаций с помощью операций алгебры логики, а так же использование констант true и false.
Перечисление (enum)
Ограничение на перечисление ркомендовано накладывать следующим образом:
// Сначала кэшируем значение enum в переменной, только потом ограничиваем
var типПерелома = ТипПерелома.Открытый;
ds.Query<Перелом>(Перелом.Views.ПереломE).Where(o => o.Тип == типПерелома).ToList();
Общие возможности и особенности
Сравнение с null
При сравнении с null доступна не только проверка на равенство и неравенство, но и работа с операциями “>”, “>=”, “<”, “<=”.
Как и при стандартной работе с Linq, выражение вида “Property > null
”, где Property
, например, типа int
, вернёт false
.
ds.Query<Лапа>(Лапа.Views.ЛапаE).Where(x => x.РазмерNullableInt > null);
Выполнение простейших арифметических операций
Внутри Linq-выражения доступно выполнение простейших арифметических операций:
string prefix = "prefix";
string postfix = "postfix";
ds.Query<Кошка>(Кошка.Views.КошкаE).Where(x => x.Кличка == prefix + postfix);
Ограничения LINQProvider
Среди крупных ограничений можно указать “проекции” (проецирование из текущего типа выборки, т.е. потомков DataObject, какого-то другого типа), а также задания ограничений с использованием группировки (Group By).
Для использования проекции или группировки необходимо:
- Получить коллекцию объектов данных, для которой требуется группировка или проекция, с помощью LINQProvider.
- Сделать дополнительный запрос к полученной коллекции с использованием LINQ to Objects.
Работа с мастерами/детейлами/псевдодетейлами
Ключи (PrimaryKey):
Для сравнения объектов по ключу необходимо использовать метод Equals
:
ds.Query<Кошка>(Кошка.Views.КошкаE).Where(o => o.__PrimaryKey.Equals(кошка.__PrimaryKey));
Мастера
Имеется возможность наложить ограничение на мастера, либо его атрибуты типа int, long, bool, string, DateTime. Например:
Порода порода = ds.Query<Порода>(Порода.Views.ПородаE).First(); // Какой-нибудь объект типа порода
Кошка кошка = ds.Query<Кошка>(Кошка.Views.КошкаE).FirstOrDefault(o => o.Порода == порода); //Получить первую кошку данной породы
Кошка кошка2 = ds.Query<Кошка>(Кошка.Views.КошкаE).FirstOrDefault(o => o.Порода.Название == "Дикая"); // Получить кошку по названию породы
При этом допускаются ограничения только на мастеров первого уровня. При попытке выполнить следующий код будет брошено исключение MasterLevelException
.
Кошка кошка = ds.Query<Кошка>(Кошка.Views.КошкаE).FirstOrDefault(o => o.Порода.ТипПороды == порода.ТипПороды); //Использование мастера мастера вызовет исключение
Но можно наложить ограничение на мастера n-го уровня по его PrimaryKey:
ds.Query<Кошка>(Кошка.Views.КошкаE).Where(o => ПородаPKs.Contains(o.Порода.ТипПороды.__PrimaryKey));
Детейлы
С учётом особенностей написания Linq-запросов к массивам детейлов:
ds.Query<Порода>(Порода.Views.КотенокE).Where(
x => x.Кошка.Лапа.Cast<Лапа>().Any(o => o.ТипЛапы.Название == "передняя")).ToList();
Псевдодетейлы
Работа с псевдодетейлами описана в статье Псевдодетейлы в LinqProvider.
Примеры использования
- Простая вычитка всех записей:
var credits = ds.Query<Кредит>(Кредит.Views.КредитL.Name);
- Наложение ограничений на строковое поле:
var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.Фамилия == "Петров");
- Наложение ограничений на дату:
var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.ДатаРождения > new DateTime(1980, 1, 1));
- Наложение ограничений на логический тип:
var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.Уволен);
- Разумеется, условия можно комбинировать:
var личности = ds.Query<Личность>(Личность.Views.ЧеловекL.Name).Where(l => l.Уволен && l.ДатаУвольнения > new DateTime(2012, 1, 1));
- Наложение ограничений на мастер (по ключу):
var кредиты = ds.Query<Кредит>(Кредит.Views.КредитL.Name).Where(k => k.Клиент == klient);
- Наложение ограничений на детейлы:
ds.Query<Порода>(Порода.Views.КотенокE).Where(x => x.Кошка.Лапа.Cast<Лапа>().Any(o => o.ТипЛапы.Название == "передняя")).ToList();