Перевод LINQ to NoSQL в Azure Cosmos DB для NoSQL
ОБЛАСТЬ ПРИМЕНЕНИЯ: NoSQL
Поставщик запросов Azure Cosmos DB выполняет сопоставление лучших усилий из запроса LINQ в запрос Azure Cosmos DB для NoSQL. Если вы хотите получить запрос NoSQL, переведенный из LINQ, используйте ToString()
метод в созданном IQueryable
объекте. В следующем описании предполагается, что вы уже имеете представление о LINQ. Помимо LINQ, Azure Cosmos DB также поддерживает Entity Framework Core, которая работает с API для NoSQL.
Примечание.
Мы рекомендуем использовать последнюю версию пакета SDK для .NET (Microsoft.Azure.Cosmos
)
Система типов поставщика запросов поддерживает только примитивные типы JSON: numeric
, , Boolean
string
и null
.
Поставщик запросов поддерживает следующие скалярные выражения:
Константы, в том числе значения примитивных типов данных в период оценки запроса.
Выражения индексов для свойств и массивов, которые обозначают свойство объекта или элемент массива. Например:
family.Id; family.children[0].familyName; family.children[0].grade;
int n = 1; family.children[n].grade;
Арифметические выражения, включая стандартные арифметические выражения по численным и логическим значениям.
2 * family.children[0].grade; x + y;
Выражения сравнения строк, в том числе сравнения строкового значения со строковой константой.
mother.familyName.StringEquals("Wakefield");
string s = "Rob"; string e = "in"; string c = "obi"; child.givenName.StartsWith(s); child.givenName.EndsWith(e); child.givenName.Contains(c);
Выражения создания объекта или массива, которые возвращают объект или массив объектов комбинированного или анонимного типа. Допускаются вложенные значения.
new Parent { familyName = "Wakefield", givenName = "Robin" }; new { first = 1, second = 2 }; //an anonymous type with two fields new int[] { 3, child.grade, 5 };
Использование LINQ
Запрос LINQ можно создать с помощью GetItemLinqQueryable
. В этом примере демонстрируется создание и асинхронное выполнение запроса LINQ с помощью FeedIterator
:
using FeedIterator<Book> setIterator = container.GetItemLinqQueryable<Book>()
.Where(b => b.Title == "War and Peace")
.ToFeedIterator<Book>());
//Asynchronous query execution
while (setIterator.HasMoreResults)
{
foreach(var item in await setIterator.ReadNextAsync()){
{
Console.WriteLine(item.cost);
}
}
Поддерживаемые операторы LINQ
Поставщик LINQ, включенный в пакет SDK noSQL .NET, поддерживает следующие операторы:
- Select: проекции преобразуются в SELECT, включая создание объектов.
- Где: фильтры преобразуют в WHERE и поддерживают перевод между
&&
,||
а также!
операторами NoSQL - SelectMany: позволяет развертывать массивы в предложение JOIN. Используйте его, чтобы сцеплять или вкладывать выражения для фильтрации по элементам массива.
- OrderBy и OrderByDescending: преобразуются в ORDER BY с модификатором ASC или DESC.
- Операторы для агрегирования Count, Sum, Min, Max, Average и их асинхронные эквиваленты CountAsync, SumAsync, MinAsync, MaxAsync и AverageAsync.
- CompareTo: выполняет преобразование в сравнение диапазонов. Этот оператор обычно используется для строк, так как они не сопоставимы в .NET.
- Skip и Take: преобразуются в OFFSET и LIMIT для ограничения числа результатов запроса и организации разбиения на страницы.
- Математические функции: поддерживается преобразование из операторов .NET
Abs
,Acos
,Asin
,Atan
,Ceiling
,Cos
,Exp
,Floor
,Log
,Log10
,Pow
,Round
,Sign
,Sin
,Sqrt
,Tan
иTruncate
в эквивалентные встроенные математические функции. - Строковые функции: поддерживается преобразование из операторов .NET
Concat
,Contains
,Count
,EndsWith
,IndexOf
,Replace
,Reverse
,StartsWith
,SubString
,ToLower
,ToUpper
,TrimEnd
иTrimStart
в эквивалентные встроенные строковые функции. - Функции массивов: поддерживается преобразование из операторов .NET
Concat
,Contains
иCount
в эквивалентные встроенные функции массивов. - Функции геопространственного расширения: поддерживается преобразование из методов-заглушек
Distance
,IsValid
,IsValidDetailed
иWithin
в эквивалентные встроенные геопространственные функции. - Функция расширения определяемой пользователем функции: поддерживает перевод из метода заглушки CosmosLinq.InvokeDefinedFunction в соответствующую определяемую пользователем функцию.
- Прочее: поддерживается преобразование
Coalesce
и условные операторы. Позволяет преобразоватьContains
в CONTAINS, ARRAY_CONTAINS или IN (в зависимости от контекста) со строковым значением.
Примеры
В следующих примерах показано, как некоторые из стандартных операторов запросов LINQ преобразуются в запросы Azure Cosmos DB.
Выбрать оператор
Синтаксис: input.Select(x => f(x))
, где f
— скалярное выражение. В данном случае input
является объектом IQueryable
.
Оператор SELECT, пример 1:
Лямбда-выражение LINQ
input.Select(family => family.parents[0].familyName);
NoSQL
SELECT VALUE f.parents[0].familyName FROM Families f
Оператор SELECT, пример 2:
Лямбда-выражение LINQ
input.Select(family => family.children[0].grade + c); // c is an int variable
NoSQL
SELECT VALUE f.children[0].grade + c FROM Families f
Оператор SELECT, пример 3:
Лямбда-выражение LINQ
input.Select(family => new { name = family.children[0].familyName, grade = family.children[0].grade + 3 });
NoSQL
SELECT VALUE { "name":f.children[0].familyName, "grade": f.children[0].grade + 3 } FROM Families f
Оператор SelectMany
Синтаксис: input.SelectMany(x => f(x))
, где f
— скалярное выражение, возвращающее тип контейнера.
Лямбда-выражение LINQ
input.SelectMany(family => family.children);
NoSQL
SELECT VALUE child FROM child IN Families.children
Оператор Where
Синтаксис: input.Where(x => f(x))
, где f
— скалярное выражение, возвращающее логическое значение.
Оператор WHERE, пример 1:
Лямбда-выражение LINQ
input.Where(family=> family.parents[0].familyName == "Wakefield");
NoSQL
SELECT * FROM Families f WHERE f.parents[0].familyName = "Wakefield"
Оператор WHERE, пример 2:
Лямбда-выражение LINQ
input.Where( family => family.parents[0].familyName == "Wakefield" && family.children[0].grade < 3);
NoSQL
SELECT * FROM Families f WHERE f.parents[0].familyName = "Wakefield" AND f.children[0].grade < 3
Составные запросы NoSQL
Вы можете объединять описанные выше операторы для создания более мощных запросов. Так как Azure Cosmos DB поддерживает вложенные контейнеры, вы можете объединить или вложить композицию.
Объединение
Синтаксис: input(.|.SelectMany())(.Select()|.Where())*
. Объединенный запрос может начинаться с необязательного запроса SelectMany
, за которым идет несколько операторов Select
или Where
.
Объединение, пример 1:
Лямбда-выражение LINQ
input.Select(family => family.parents[0]) .Where(parent => parent.familyName == "Wakefield");
NoSQL
SELECT * FROM Families f WHERE f.parents[0].familyName = "Wakefield"
Объединение, пример 2:
Лямбда-выражение LINQ
input.Where(family => family.children[0].grade > 3) .Select(family => family.parents[0].familyName);
NoSQL
SELECT VALUE f.parents[0].familyName FROM Families f WHERE f.children[0].grade > 3
Объединение, пример 3:
Лямбда-выражение LINQ
input.Select(family => new { grade=family.children[0].grade}). Where(anon=> anon.grade < 3);
NoSQL
SELECT * FROM Families f WHERE ({grade: f.children[0].grade}.grade > 3)
Объединение, пример 4:
Лямбда-выражение LINQ
input.SelectMany(family => family.parents) .Where(parent => parents.familyName == "Wakefield");
NoSQL
SELECT * FROM p IN Families.parents WHERE p.familyName = "Wakefield"
Вложенные операторы
Используется синтаксис input.SelectMany(x=>x.Q())
, где Q
является оператором Select
, SelectMany
или Where
.
Вложенный запрос применяет внутренний запрос к каждому элементу внешнего контейнера. Одной из важных особенностей является то, что внутренний запрос может ссылаться на поля элементов во внешнем контейнере, как при самосоединении.
Вложенность, пример 1:
Лямбда-выражение LINQ
input.SelectMany(family=> family.parents.Select(p => p.familyName));
NoSQL
SELECT VALUE p.familyName FROM Families f JOIN p IN f.parents
Вложенность, пример 2:
Лямбда-выражение LINQ
input.SelectMany(family => family.children.Where(child => child.familyName == "Jeff"));
NoSQL
SELECT * FROM Families f JOIN c IN f.children WHERE c.familyName = "Jeff"
Вложенность, пример 3:
Лямбда-выражение LINQ
input.SelectMany(family => family.children.Where( child => child.familyName == family.parents[0].familyName));
NoSQL
SELECT * FROM Families f JOIN c IN f.children WHERE c.familyName = f.parents[0].familyName