Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Basisbeginselen opvragen
EF Core LINQ-query's kunnen op dezelfde manier worden uitgevoerd op Azure Cosmos DB als voor andere databaseproviders. Voorbeeld:
public class Session
{
public Guid Id { get; set; }
public string Category { get; set; }
public string TenantId { get; set; } = null!;
public Guid UserId { get; set; }
public int SessionId { get; set; }
}
var stringResults = await context.Sessions
.Where(
e => e.Category.Length > 4
&& e.Category.Trim().ToLower() != "disabled"
&& e.Category.TrimStart().Substring(2, 2).Equals("xy", StringComparison.OrdinalIgnoreCase))
.ToListAsync();
Opmerking
De Azure Cosmos DB-provider vertaalt niet dezelfde set LINQ-query's als andere providers.
De EF-operator Include() wordt bijvoorbeeld niet ondersteund in Azure Cosmos DB, omdat query's voor meerdere documenten niet worden ondersteund in de database.
Partitiesleutels
Het voordeel van partitioneren is om uw query's alleen uit te voeren op de partitie waar de relevante gegevens worden gevonden, kosten te besparen en snellere resultaatsnelheid te garanderen. Query's die geen partitiesleutels opgeven, worden uitgevoerd op alle partities, wat behoorlijk kostbaar kan zijn.
Vanaf EF 9.0 detecteert en extraheert EF automatisch partitiesleutelvergelijkingen in de operators van Where uw LINQ-query. Stel dat we de volgende query uitvoeren op ons Session entiteitstype, dat is geconfigureerd met een hiërarchische partitiesleutel:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Session>()
.HasPartitionKey(b => new { b.TenantId, b.UserId, b.SessionId })
}
var tenantId = "Microsoft";
var userId = new Guid("00aa00aa-bb11-cc22-dd33-44ee44ee44ee");
var username = "scott";
var sessions = await context.Sessions
.Where(
e => e.TenantId == tenantId
&& e.UserId == userId
&& e.SessionId > 0
&& e.Username == username)
.ToListAsync();
Als we de logboeken bekijken die door EF worden gegenereerd, zien we dat deze query als volgt wordt uitgevoerd:
Executed ReadNext (166.6985 ms, 2.8 RU) ActivityId='312da0d2-095c-4e73-afab-27072b5ad33c', Container='test', Partition='["Microsoft","00aa00aa-bb11-cc22-dd33-44ee44ee44ee"]', Parameters=[]
SELECT VALUE c
FROM root c
WHERE ((c["SessionId"] > 0) AND CONTAINS(c["Username"], "a"))
In deze logboeken zien we het volgende:
- De eerste twee vergelijkingen , aan
TenantIdenUserId- zijn verwijderd en worden weergegeven in deReadNextpartitie in plaats van in deWHEREcomponent. Dit betekent dat de query alleen wordt uitgevoerd op de subpartities voor deze waarden. -
SessionIdmaakt ook deel uit van de hiërarchische partitiesleutel, maar in plaats van een gelijkheidsvergelijking maakt het gebruik van een operator groter dan (>) en kan daarom niet worden verwijderd. Het maakt deel uit van deWHEREcomponent zoals elke gewone eigenschap. -
Usernameis een gewone eigenschap , geen deel van de partitiesleutel - en blijft daarom ook in deWHEREcomponent.
Houd er rekening mee dat hoewel sommige partitiesleutelwaarden niet worden opgegeven, hiërarchische partitiesleutels nog steeds alleen gericht zijn op de subpartities die overeenkomen met de eerste twee eigenschappen. Hoewel dit niet zo efficiënt is als het richten op één partitie (zoals geïdentificeerd door alle drie de eigenschappen), is het nog steeds veel efficiënter dan het instellen van alle partities.
In plaats van te verwijzen naar eigenschappen van partitiesleutels in een Where operator, kunt u deze expliciet opgeven met behulp van de WithPartitionKey operator:
var sessions = await context.Sessions
.WithPartitionKey(tenantId, userId)
.Where(e => e.SessionId > 0 && e.Username.Contains("a"))
.ToListAsync();
Dit wordt op dezelfde manier uitgevoerd als de bovenstaande query en kan de voorkeur hebben als u partitiesleutels explicieter wilt maken in uw query's. Het gebruik WithPartitionKey kan nodig zijn in versies van EF vóór 9.0: houd de logboeken in de gaten om ervoor te zorgen dat query's partitiesleutels gebruiken zoals verwacht.
Puntleesbewerkingen
Hoewel Azure Cosmos DB krachtige query's via SQL mogelijk maakt, kunnen dergelijke query's behoorlijk duur zijn. Azure Cosmos DB ondersteunt ook puntleesbewerkingen, die moeten worden gebruikt bij het ophalen van één document als zowel de id eigenschap als de volledige partitiesleutel bekend zijn. Punt leest rechtstreeks een specifiek document in een specifieke partitie en voert zeer efficiënt uit en met lagere kosten vergeleken met het ophalen van hetzelfde document met een query. Het is raadzaam om uw systeem zo vaak mogelijk te ontwerpen om puntleesbewerkingen te gebruiken. Raadpleeg de Documentatie van Azure Cosmos DB voor meer informatie.
In de vorige sectie hebben we EF gezien dat vergelijkingen van partitiesleutels uit de Where component worden geïdentificeerd en geëxtraheerd voor efficiëntere query's, waardoor de verwerking alleen wordt beperkt tot de relevante partities. Het is mogelijk om nog een stap verder te gaan en ook de id eigenschap in de query op te geven. Laten we de volgende query bekijken:
var session = await context.Sessions.SingleAsync(
e => e.Id == someId
&& e.TenantId == tenantId
&& e.UserId == userId
&& e.SessionId == sessionId);
In deze query wordt een waarde voor de Id eigenschap opgegeven (die is toegewezen aan de eigenschap Azure Cosmos DB id ), evenals waarden voor alle eigenschappen van de partitiesleutel. Bovendien zijn er geen extra onderdelen voor de query. Wanneer aan al deze voorwaarden wordt voldaan, kan EF de query uitvoeren als puntleespunt:
Executed ReadItem (46 ms, 1 RU) ActivityId='d7391311-2266-4811-ae2d-535904c42c43', Container='test', Id='9', Partition='["Microsoft","00aa00aa-bb11-cc22-dd33-44ee44ee44ee",10.0]'
Let op, ReadItemwat aangeeft dat de query is uitgevoerd als een efficiënt punt lezen. Er is geen SQL-query betrokken.
Zoals bij het extraheren van partitiesleutels zijn belangrijke verbeteringen aangebracht in dit mechanisme in EF 9.0; oudere versies detecteren en gebruiken geen puntleesbewerkingen betrouwbaar.
Pagina-indeling
Opmerking
Deze functie is geïntroduceerd in EF Core 9.0 en is nog steeds experimenteel. Laat ons weten hoe het voor u werkt en als u feedback hebt.
Paginering verwijst naar het ophalen van resultaten in pagina's, in plaats van allemaal tegelijk; Dit wordt meestal gedaan voor grote resultatensets, waarbij een gebruikersinterface wordt weergegeven, zodat gebruikers door pagina's van de resultaten kunnen navigeren.
Een veelgebruikte manier om paginering met databases te implementeren, is door de Skip operators en Take LINQ-operators (OFFSET en LIMIT in SQL) te gebruiken. Op basis van een paginaformaat van 10 resultaten kan de derde pagina als volgt worden opgehaald met EF Core:
var position = 20;
var nextPage = await context.Session
.OrderBy(s => s.Id)
.Skip(position)
.Take(10)
.ToListAsync();
Helaas is deze techniek behoorlijk inefficiënt en kan de querykosten aanzienlijk verhogen. Azure Cosmos DB biedt een speciaal mechanisme voor het pagineren van het resultaat van een query, via het gebruik van vervolgtokens:
CosmosPage firstPage = await context.Sessions
.OrderBy(s => s.Id)
.ToPageAsync(pageSize: 10, continuationToken: null);
string continuationToken = firstPage.ContinuationToken;
foreach (var session in firstPage.Values)
{
// Display/send the sessions to the user
}
In plaats van de LINQ-query met ToListAsync of vergelijkbaar te beëindigen, gebruiken we de ToPageAsync methode om deze maximaal 10 items op elke pagina op te halen (houd er rekening mee dat er mogelijk minder items in de database zijn). Omdat dit de eerste query is, willen we resultaten van het begin ophalen en doorgeven null als het vervolgtoken.
ToPageAsync retourneert een CosmosPage<T>, waarmee een vervolgtoken en de waarden op de pagina worden weergegeven (maximaal 10 items). Uw programma verzendt deze waarden doorgaans naar de client, samen met het vervolgtoken; Hierdoor kan de query later worden hervat en meer resultaten worden opgehaald.
Stel dat de gebruiker nu op de knop Volgende in de gebruikersinterface klikt en vraagt om de volgende 10 items. Vervolgens kunt u de query als volgt uitvoeren:
CosmosPage nextPage = await context.Sessions.OrderBy(s => s.Id).ToPageAsync(10, continuationToken);
string continuationToken = nextPage.ContinuationToken;
foreach (var session in nextPage.Values)
{
// Display/send the sessions to the user
}
We voeren dezelfde query uit, maar deze keer geven we het vervolgtoken door dat is ontvangen van de eerste uitvoering; hiermee wordt de query-engine geïnstrueerd om door te gaan met de query waar deze was gebleven en de volgende 10 items op te halen. Zodra we de laatste pagina hebben opgehaald en er geen resultaten meer zijn, wordt het vervolgtoken weergegeven nullen kan de knop 'Volgende' grijs worden weergegeven. Deze pagineringsmethode is uiterst efficiënt en rendabel in vergelijking met het gebruik Skip en Take.
Zie deze pagina voor meer informatie over paginering in Azure Cosmos DB.
Opmerking
Azure Cosmos DB biedt geen ondersteuning voor achterwaartse paginering en biedt geen telling van het totale aantal pagina's of items.
ToPageAsync wordt momenteel geannoteerd als experimenteel, omdat deze kan worden vervangen door een meer algemene EF-paginerings-API die niet specifiek is voor Azure Cosmos DB. Hoewel het gebruik van de huidige API een compilatiewaarschuwing genereert (EF9102), moet dit veilig zijn. Toekomstige wijzigingen vereisen mogelijk kleine aanpassingen in de API-shape.
FindAsync
FindAsync is een nuttige API voor het ophalen van een entiteit door de primaire sleutel en het vermijden van een retour van een database wanneer de entiteit al is geladen en wordt bijgehouden door de context.
Ontwikkelaars die bekend zijn met relationele databases, worden gebruikt voor de primaire sleutel van een entiteitstype dat bestaat uit bijvoorbeeld een Id eigenschap. Wanneer u de EF Azure Cosmos DB-provider gebruikt, bevat de primaire sleutel de eigenschappen van de partitiesleutel naast de eigenschap die is toegewezen aan de JSON-eigenschap id . Dit is het geval omdat Azure Cosmos DB verschillende partities toestaat documenten met dezelfde JSON-eigenschap id te bevatten, en dus alleen de gecombineerde id en partitiesleutel uniek één document in een container identificeren:
public class Session
{
public Guid Id { get; set; }
public string PartitionKey { get; set; }
...
}
var mySession = await context.FindAsync(id, pkey);
Als u een hiërarchische partitiesleutel hebt, moet u alle partitiesleutelwaarden doorgeven aan FindAsync, in de volgorde waarin ze zijn geconfigureerd.
Opmerking
Gebruik FindAsync alleen wanneer de entiteit mogelijk al door uw context wordt bijgehouden en u de retour van de database wilt vermijden.
Gebruik anders gewoon SingleAsync : er is geen prestatieverschil tussen de twee wanneer de entiteit moet worden geladen vanuit de database.
SQL-query's
Query's kunnen ook rechtstreeks in SQL worden geschreven. Voorbeeld:
var rating = 3;
_ = await context.Blogs
.FromSql($"SELECT VALUE c FROM root c WHERE c.Rating > {rating}")
.ToListAsync();
Deze query resulteert in de volgende queryuitvoering:
SELECT VALUE s
FROM (
SELECT VALUE c FROM root c WHERE c.Angle1 <= @p0
) s
Houd er rekening mee dat FromSql is geïntroduceerd in EF 9.0. In eerdere versies kan in plaats daarvan FromSqlRaw worden gebruikt, hoewel u er rekening mee houdt dat deze methode kwetsbaar is voor SQL-injectieaanvallen.
Zie de relationele documentatie over SQL-query's voor meer informatie over SQL-query's. de meeste inhoud is ook relevant voor de Azure Cosmos DB-provider.
Functietoewijzingen
In deze sectie ziet u welke .NET-methoden en -leden worden vertaald in welke SQL-functies worden uitgevoerd bij het uitvoeren van query's met de Azure Cosmos DB-provider.
Datum- en tijdfuncties
| .NET | SQL | Toegevoegd in |
|---|---|---|
| DateTime.UtcNow | GetCurrentDateTime() | |
| DateTimeOffset.UtcNow | GetCurrentDateTime() | |
| dateTime.Year1 | DateTimePart("yyyy", dateTime) | EF 9 |
| dateTimeOffset.Year1 | DateTimePart("yyyy", dateTimeOffset) | EF 9 |
| dateTime.AddYears(years)1 | DateTimeAdd("yyyy", dateTime) | EF 9 |
| dateTimeOffset.AddYears(years)1 | DateTimeAdd("yyyy", dateTimeOffset) | EF 9 |
1 De andere leden van het onderdeel worden ook vertaald (Maand, Dag...).
Numerieke functies
| .NET | SQL |
|---|---|
| dubbel. DegreesToRadians(x) | RADIALEN(@x) |
| dubbel. RadiansToDegrees(x) | DEGREES(@x) |
| EF. Functions.Random() | RAND() |
| Math.Abs(waarde) | ABS(@value) |
| Math.Acos(d) | ACOS(@d) |
| Math.Asin(d) | ASIN(@d) |
| Math.Atan(d) | ATAN(@d) |
| Math.Atan2(y, x) | ATN2(@y, @x) |
| Math.Ceiling(d) | PLAFOND(@d) |
| Math.Cos(d) | COS(@d) |
| Math.Exp(d) | EXP(@d) |
| Math.Floor(d) | FLOOR(@d) |
| Math.Log(a, newBase) | LOG(@a, @newBase) |
| Math.Log(d) | LOG(@d) |
| Math.Log10(d) | LOG10(@d) |
| Math.Pow(x, y) | POWER(@x, @y) |
| Math.Round(d) | ROUND(@d) |
| Math.Sign(waarde) | SIGN(@value) |
| Math.Sin(a) | SIN(@a) |
| Math.Sqrt(d) | SQRT(@d) |
| Math.Tan(a) | TAN(@a) |
| Math.Truncate(d) | TRUNC(@d) |
Aanbeveling
Naast de hier vermelde methoden worden ook algemene wiskundige implementaties en MathF-methoden vertaald. Bijvoorbeeld, Math.SinMathF.Sin, double.Sinen float.Sin alle toewijzingen aan de SIN functie in SQL.
Stringfuncties
| .NET | SQL | Toegevoegd in |
|---|---|---|
| Regex.IsMatch(invoer, patroon) | RegexMatch(@pattern, @input) | |
| Regex.IsMatch(invoer, patroon, opties) | RegexMatch(@input, @pattern, @options) | |
| snaar. Concat(str0, str1) | @str0 + @str1 | |
| snaar. Is gelijk aan(a, b, StringComparison.Ordinaal) | STRINGEQUALS(@a, @b) | |
| snaar. Is gelijk aan(a, b, StringComparison.OrdinalIgnoreCase) | STRINGEQUALS(@a, @b, true) | |
| stringValue.Contains(value) | CONTAINS(@stringValue, @value) | |
| stringValue.Contains(value, StringComparison.Ordinal) | CONTAINS(@stringValue, @value, false) | EF 9 |
| stringValue.Contains(value, StringComparison.OrdinalIgnoreCase) | CONTAINS(@stringValue, @value, true) | EF 9 |
| stringValue.EndsWith(value) | ENDSWITH(@stringValue, @value) | |
| stringValue.EndsWith(waarde, StringComparison.Ordinal) | ENDSWITH(@stringValue, @value, false) | EF 9 |
| stringValue.EndsWith(waarde, StringComparison.OrdinalIgnoreCase) | ENDSWITH(@stringValue, @value, true) | EF 9 |
| stringValue.Equals(value, StringComparison.Ordinal) | STRINGEQUALS(@stringValue, @value) | |
| stringValue.Equals(value, StringComparison.OrdinalIgnoreCase) | STRINGEQUALS(@stringValue, @value, true) | |
| stringValue.FirstOrDefault() | LINKS(@stringValue, 1) | |
| stringValue.IndexOf(value) | INDEX_OF(@stringValue, @value) | |
| stringValue.IndexOf(value, startIndex) | INDEX_OF(@stringValue, @value, @startIndex) | |
| stringValue.LastOrDefault() | RECHTS(@stringValue, 1) | |
| stringValue.Length | LENGTE(@stringValue) | |
| stringValue.Replace(oldValue, newValue) | REPLACE(@stringValue, @oldValue, @newValue) | |
| stringValue.StartsWith(value) | STARTSWITH(@stringValue, @value) | |
| stringValue.StartsWith(value, StringComparison.Ordinal) | STARTSWITH(@stringValue, @value, false) | EF 9 |
| stringValue.StartsWith(value, StringComparison.OrdinalIgnoreCase) | STARTSWITH(@stringValue, @value, true) | EF 9 |
| stringValue.Substring(startIndex) | SUBSTRING(@stringValue, @startIndex, LENGTH(@stringValue)) | |
| stringValue.Substring(startIndex, length) | SUBSTRING(@stringValue, @startIndex, @length) | |
| stringValue.ToLower() | LOWER(@stringValue) | |
| stringValue.ToUpper() | UPPER(@stringValue) | |
| stringValue.Trim() | TRIM(@stringValue) | |
| stringValue.TrimEnd() | RTRIM(@stringValue) | |
| stringValue.TrimStart() | LTRIM(@stringValue) |
Vector en zoeken in volledige tekst
| .NET | SQL | Toegevoegd in |
|---|---|---|
| VectorDistance(vector1, vector2). | VectorDistance(vector1, vector2) | EF 9 |
| VectorDistance(vector1, vector2, bruteForce) | VectorDistance(vector1, vector2, bruteForce) | EF 9 |
| VectorDistance(vector1, vector2, bruteForce, distanceFunction) | VectorDistance(vector1, vector2, bruteForce, distanceFunction) | EF 9 |
| FullTextContains(eigenschap, trefwoord) | FullTextContains(eigenschap, trefwoord) | EF 10 |
| FullTextContainsAll(eigenschap, trefwoord1, trefwoord2) | FullTextContainsAll(eigenschap, trefwoord1, trefwoord2) | EF 10 |
| FullTextContainsAny(eigenschap, trefwoord1, trefwoord2) | FullTextContainsAny(eigenschap, trefwoord1, trefwoord2) | EF 10 |
| FullTextScore(eigenschap, trefwoord1, trefwoord2) | FullTextScore(eigenschap, trefwoord1, trefwoord2) | EF 10 |
| Rrf(search1, search2) | RRF(eigenschap, search1, search2). | EF 10 |
| Rrf(new[] { search1, search2 }, gewichten) | RRF(eigenschap, search1, search2, gewichten) | EF 10 |
Zie de documentatie voor meer informatie over vectorzoekopdrachten. Zie de documentatie voor meer informatie over zoeken in volledige tekst.
Diverse functies
| .NET | SQL | Toegevoegd in |
|---|---|---|
| collectie. Contains(item) | @item in @collection | |
| CoalesceUndefined(x, y)1 | x ?? y | EF 9 |
| IsDefined(x) | IS_DEFINED(x) | EF 9 |
1 Houd er rekening mee CoalesceUndefineddat undefined samensnommen , niet null. Als u wilt samenvoegen null, gebruikt u de reguliere C# ?? -operator.