Delen via


Belangrijke wijzigingen in EF Core 3.x

De volgende API- en gedragswijzigingen hebben het potentieel om bestaande toepassingen te verbreken bij het upgraden naar 3.x. Wijzigingen die we verwachten alleen van invloed te zijn op databaseproviders, worden gedocumenteerd onder providerwijzigingen.

Samenvatting

Brekende wijziging impact
LINQ-query's worden niet meer geëvalueerd op de client Hoog
Het opdrachtregelprogramma EF Core, dotnet ef, maakt niet langer deel uit van de .NET Core SDK- Hoog
DetectChanges respecteert door de opslag gegenereerde sleutelwaarden Hoog
De naam van FromSql, ExecuteSql en ExecuteSqlAsync is gewijzigd Hoog
Querytypen worden samengevoegd met entiteitstypen Hoog
Entity Framework Core maakt geen deel meer uit van het gedeelde framework ASP.NET Core Gemiddeld
trapsgewijs verwijderen gebeurt nu standaard onmiddellijk Gemiddeld
Het laden van gerelateerde entiteiten vindt nu plaats in één query Gemiddeld
DeleteBehavior.Restrict heeft schonere semantiek Gemiddeld
Configuratie-API voor eigendomstype-relaties zijn gewijzigd Gemiddeld
Elke eigenschap maakt gebruik van onafhankelijke geheugengebaseerde generering van integer-sleutels Gemiddeld
Geen traceringsquery's voeren nog een identiteitsresolutie uit Gemiddeld
metagegevens-API-wijzigingen Gemiddeld
providerspecifieke metagegevens-API-wijzigingen Gemiddeld
UseRowNumberForPaging is verwijderd Gemiddeld
FromSql-methode wanneer deze wordt gebruikt met een opgeslagen procedure, kan niet worden samengesteld Gemiddeld
FromSql-methoden kunnen alleen worden opgegeven voor querywortels Laag
Tijdelijke sleutelwaarden worden niet meer ingesteld op entiteitsexemplaren Laag
Afhankelijke eenheden die de tabel delen met de principaal zijn nu optioneel Laag
Alle entiteiten die een tabel met een gelijktijdigheidstokenkolom delen, moeten deze toewijzen aan een eigenschap Laag
Eigendom entiteiten kunnen niet worden opgevraagd zonder dat de eigenaar een tracking-aanvraag gebruikt Laag
Overgenomen eigenschappen van niet-gemapte typen worden nu toegewezen aan één kolom voor alle afgeleide typen Laag
De refererende-sleutelconventie komt niet meer overeen met dezelfde naam als de principal-eigenschap Laag
Databaseverbinding is nu gesloten als deze niet meer wordt gebruikt voordat de TransactionScope is voltooid Laag
Backing fields worden standaard gebruikt Laag
Gooi als er meerdere compatibele backing-velden worden gevonden Laag
Eigenschapsnamen die alleen voor velden zijn, moeten overeenkomen met de veldnaam Laag
AddDbContext/AddDbContextPool roept AddLogging en AddMemoryCache niet meer aan Laag
AddEntityFramework* voegt IMemoryCache toe met een groottelimiet Laag
DbContext.Entry voert nu lokaal DetectChanges uit Laag
tekenreeks- en bytematrixsleutels worden niet standaard door de client gegenereerd Laag
ILoggerFactory is nu een ge-scopede service Laag
Lazy-loading proxys gaan er niet langer van uit dat navigatie-eigenschappen volledig zijn geladen Laag
Overmatige creatie van interne serviceproviders is nu standaard een fout Laag
Nieuw gedrag voor HasOne/HasMany aangeroepen met één tekenreeks Laag
Het retourtype voor verschillende asynchrone methoden is gewijzigd van Taak in ValueTask Laag
De aantekening Relational:TypeMapping is nu gewoon TypeMapping Laag
ToTable op een afgeleid type genereert een uitzondering Laag
EF Core verzendt geen pragma meer voor SQLite FK-afdwinging Laag
Microsoft.EntityFrameworkCore.Sqlite is nu afhankelijk van SQLitePCLRaw.bundle_e_sqlite3 Laag
Guid-waarden worden nu opgeslagen als TEKST op SQLite Laag
tekenwaarden worden nu opgeslagen als TEKST op SQLite Laag
migratie-id's worden nu gegenereerd met behulp van de agenda van de invariante cultuur Laag
Extensiegegevens/metagegevens zijn verwijderd uit IDbContextOptionsExtension Laag
De naam van LogQueryPossibleExceptionWithAggregateOperator is gewijzigd Laag
API verduidelijken voor namen van beperkingen voor vreemde sleutels Laag
IRelationalDatabaseCreator.HasTables/HasTablesAsync zijn openbaar gemaakt Laag
Microsoft.EntityFrameworkCore.Design is nu een DevelopmentDependency-pakket Laag
SQLitePCL.raw bijgewerkt naar versie 2.0.0 Laag
NetTopologySuite bijgewerkt naar versie 2.0.0 Laag
Microsoft.Data.SqlClient wordt gebruikt in plaats van System.Data.SqlClient Laag
Meerdere dubbelzinnige zelfverwijzende relaties moeten worden geconfigureerd Laag
Wanneer DbFunction.Schema null is of een lege tekenreeks, wordt het geconfigureerd in het standaardschema van het model Laag
EF Core 3.0 is gericht op .NET Standard 2.1 in plaats van .NET Standard 2.0
Uitvoering van query's wordt vastgelegd op foutopsporingsniveau Hersteld

Wijzigingen met hoge impact

LINQ-query's worden niet meer geëvalueerd op de client

Probleem bijhouden #14935Zie ook probleem #12795

Oud gedrag

Voordat 3.0, wanneer EF Core een expressie die deel uitmaakte van een query niet kon converteren naar SQL of een parameter, werd de expressie automatisch op de client geëvalueerd. Standaard heeft clientevaluatie van mogelijk dure expressies alleen een waarschuwing geactiveerd.

Nieuw gedrag

Vanaf 3.0 staat EF Core alleen expressies toe in de projectie op het hoogste niveau (de laatste Select() aanroep in de query) op de client te evalueren. Wanneer expressies in een ander deel van de query niet kunnen worden geconverteerd naar SQL of een parameter, wordt er een uitzondering gegenereerd.

Waarom

Met automatische clientevaluatie van query's kunnen veel query's worden uitgevoerd, zelfs als belangrijke onderdelen ervan niet kunnen worden vertaald. Dit gedrag kan leiden tot onverwacht en mogelijk schadelijk gedrag dat alleen in productie kan worden weergegeven. Een voorwaarde in een Where()-aanroep die niet kan worden vertaald, kan er bijvoorbeeld toe leiden dat alle rijen uit de tabel worden overgedragen van de databaseserver en dat het filter wordt toegepast op de client. Deze situatie kan gemakkelijk onopgemerkt blijven als de tabel tijdens de ontwikkeling slechts een paar rijen heeft, maar zwaar weegt wanneer de toepassing naar productie gaat, waarbij de tabel mogelijk miljoenen rijen bevat. Clientevaluatiewaarschuwingen zijn ook te gemakkelijk te negeren tijdens de ontwikkeling.

Daarnaast kan automatische clientevaluatie leiden tot problemen waarbij het verbeteren van queryomzetting voor specifieke expressies onbedoelde wijzigingen tussen releases veroorzaakte.

Maatregelen

Als een query niet volledig kan worden vertaald, herschrijft u de query in een formulier dat kan worden vertaald, of gebruikt u AsEnumerableAsync(), ToListAsync()of vergelijkbaar met het expliciet terugbrengen van gegevens naar de client, waar deze vervolgens verder kan worden verwerkt met LINQ-to-Objects.

Wijzigingen met gemiddelde impact

Entity Framework Core maakt geen deel meer uit van het gedeelde ASP.NET Core-framework

Aankondigingen van problemen bijhouden#325

Oud gedrag

Voordat ASP.NET Core 3.0, wanneer u een pakketverwijzing aan Microsoft.AspNetCore.App of Microsoft.AspNetCore.Allhebt toegevoegd, zou dit EF Core en enkele EF Core-gegevensproviders zoals de SQL Server-provider bevatten.

Nieuw gedrag

Vanaf 3.0 bevat het gedeelde ASP.NET Core-framework geen EF Core- of EF Core-gegevensproviders.

Waarom

Voordat deze wijziging werd doorgevoerd, waren er verschillende stappen nodig om EF Core te verkrijgen, afhankelijk van of de toepassing gericht was op ASP.NET Core en SQL Server. Bovendien dwong het upgraden van ASP.NET Core de upgrade van EF Core en de SQL Server-provider af, wat niet altijd wenselijk is.

Met deze wijziging is de ervaring van het verkrijgen van EF Core hetzelfde voor alle providers, ondersteunde .NET-implementaties en toepassingstypen. Ontwikkelaars kunnen nu ook precies bepalen wanneer EF Core- en EF Core-gegevensproviders worden bijgewerkt.

Maatregelen

Als u EF Core wilt gebruiken in een ASP.NET Core 3.0-toepassing of een andere ondersteunde toepassing, voegt u expliciet een pakketverwijzing toe aan de EF Core-databaseprovider die door uw toepassing wordt gebruikt.

Het EF Core-opdrachtregelprogramma, dotnet ef, maakt niet langer deel uit van de .NET Core SDK

Probleem bijhouden #14016

Oud gedrag

Vóór 3.0 was het hulpprogramma dotnet ef opgenomen in de .NET Core SDK en was het direct beschikbaar voor gebruik vanaf de opdrachtregel vanuit een project zonder extra stappen.

Nieuw gedrag

Vanaf 3.0 bevat de .NET SDK het hulpprogramma dotnet ef niet, dus voordat u het kunt gebruiken, moet u deze expliciet installeren als een lokaal of globaal hulpprogramma.

Waarom

Met deze wijziging kunnen we dotnet ef distribueren en bijwerken als een gewoon .NET CLI-hulpprogramma op NuGet, consistent met het feit dat de EF Core 3.0 ook altijd wordt gedistribueerd als een NuGet-pakket.

Oplossingen

Als je migraties of een DbContextwilt beheren, installeer dotnet-ef als globaal hulpprogramma.

dotnet tool install --global dotnet-ef

U kunt het ook een lokaal hulpprogramma verkrijgen wanneer u de afhankelijkheden van een project herstelt die het declareert als een tooling-afhankelijkheid met behulp van een manifestbestand van een hulpprogramma.

Wijzigingen met lage impact

De naam van FromSql, ExecuteSql en ExecuteSqlAsync is gewijzigd

probleem bijhouden #10996

Belangrijk

ExecuteSqlCommand en ExecuteSqlCommandAsync zijn afgeschaft. Gebruik in plaats daarvan deze methoden.

Oud gedrag

Vóór EF Core 3.0 zijn deze methodenamen overbelast om te werken met een normale tekenreeks of een tekenreeks die moet worden geïnterpoleerd in SQL en parameters.

Nieuw gedrag

Gebruik vanaf EF Core 3.0 FromSqlRaw, ExecuteSqlRawen ExecuteSqlRawAsync om een geparameteriseerde query te maken waarbij de parameters afzonderlijk van de querytekenreeks worden doorgegeven. Bijvoorbeeld:

context.Products.FromSqlRaw(
    "SELECT * FROM Products WHERE Name = {0}",
    product.Name);

Gebruik FromSqlInterpolated, ExecuteSqlInterpolateden ExecuteSqlInterpolatedAsync om een geparameteriseerde query te maken waarin de parameters worden doorgegeven als onderdeel van een geïnterpoleerde querytekenreeks. Bijvoorbeeld:

context.Products.FromSqlInterpolated(
    $"SELECT * FROM Products WHERE Name = {product.Name}");

Houd er rekening mee dat beide bovenstaande query's dezelfde geparameteriseerde SQL met dezelfde SQL-parameters produceren.

Waarom

Methode-overbelastingen zoals deze maken het heel eenvoudig om per ongeluk de onbewerkte tekenreeksmethode aan te roepen wanneer de intentie was om de geïnterpoleerde tekenreeksmethode aan te roepen, en andersom. Dit kan ertoe leiden dat query's niet worden geparameteriseerd wanneer ze zouden moeten zijn.

Maatregelen

Schakel over naar de nieuwe methodenamen.

De FromSql-methode bij gebruik met opgeslagen procedure kan niet worden samengesteld

Volgprobleem #15392

Oud gedrag

Vóór EF Core 3.0 probeerde de FromSql-methode te detecteren of de doorgegeven SQL kon worden samengesteld. Er werd clientevaluatie uitgevoerd toen de SQL niet-samenstelbaar was, zoals bij een opgeslagen procedure. De volgende query heeft gewerkt door de opgeslagen procedure uit te voeren op de server en FirstOrDefault aan de clientzijde uit te voeren.

context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").FirstOrDefault();

Nieuw gedrag

Vanaf EF Core 3.0 probeert EF Core de SQL niet te parseren. Dus als u na FromSqlRaw/FromSqlInterpolated opstelt, zal EF Core de SQL samenstellen door een subquery te genereren. Dus als u een opgeslagen procedure met samenstelling gebruikt, krijgt u een uitzondering voor ongeldige SQL-syntaxis.

Waarom

EF Core 3.0 biedt geen ondersteuning voor automatische clientevaluatie, omdat deze foutgevoelig was, zoals hier wordt uitgelegd hier.

Maatregelen

Als u een opgeslagen procedure gebruikt in FromSqlRaw/FromSqlInterpolated, weet u dat deze niet kan worden samengesteld, zodat u AsEnumerable/AsAsyncEnumerable direct na de aanroep van de FromSql-methode kunt toevoegen om elke samenstelling aan de serverzijde te voorkomen.

context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").AsEnumerable().FirstOrDefault();

FromSql-methoden kunnen alleen worden opgegeven in queryroots

probleem bijhouden #15704

Oud gedrag

Vóór EF Core 3.0 kan de methode FromSql overal in de query worden opgegeven.

Nieuw gedrag

Vanaf EF Core 3.0 kunnen de nieuwe FromSqlRaw- en FromSqlInterpolated methoden (die FromSqlvervangen) alleen worden opgegeven op querywortels, dat wil bijvoorbeeld rechtstreeks op de DbSet<>. Als u ze ergens anders probeert op te geven, treedt er een compilatiefout op.

Waarom

Het opgeven van FromSql ergens anders dan op een DbSet geen toegevoegde betekenis of toegevoegde waarde had, en kan in bepaalde scenario's dubbelzinnigheid veroorzaken.

Maatregelen

FromSql aanroepen moeten rechtstreeks worden verplaatst naar de DbSet waarop ze van toepassing zijn.

Geen traceringsquery's meer uitvoeren om identiteitsomzetting uit te voeren

Volgnummer probleem #13518

Oud gedrag

Vóór EF Core 3.0 zou hetzelfde entiteitsexemplaar worden gebruikt voor elk exemplaar van een entiteit met een bepaald type en id. Dit komt overeen met het gedrag van het bijhouden van query's. Bijvoorbeeld deze query:

var results = await context.Products.Include(e => e.Category).AsNoTracking().ToListAsync();

retourneert dezelfde Category instantie voor elke Product die is gekoppeld aan de opgegeven categorie.

Nieuw gedrag

Vanaf EF Core 3.0 worden verschillende entiteitsexemplaren gemaakt wanneer een entiteit met een bepaald type en id op verschillende plaatsen in de geretourneerde grafiek wordt aangetroffen. De bovenstaande query retourneert bijvoorbeeld nu een nieuw Category exemplaar voor elke Product, zelfs wanneer twee producten aan dezelfde categorie zijn gekoppeld.

Waarom

Identiteitsomzetting (dat wil gezegd, bepalend dat een entiteit hetzelfde type en dezelfde id heeft als een eerder aangetroffen entiteit) voegt extra prestatie- en geheugenoverhead toe. Dit gaat meestal in tegen de reden waarom query's zonder tracering in de eerste plaats worden gebruikt. Hoewel identiteitsomzetting soms nuttig kan zijn, is het niet nodig als de entiteiten moeten worden geserialiseerd en verzonden naar een client, wat gebruikelijk is voor query's zonder tracering.

Maatregelen

Gebruik een traceringsquery indien identiteitsresolutie is vereist.

Tijdelijke sleutelwaarden worden niet meer ingesteld op entiteitsexemplaren

probleem bijhouden #12378

Oud gedrag

Vóór EF Core 3.0 werden tijdelijke waarden toegewezen aan alle sleuteleigenschappen die later een echte waarde zouden hebben die door de database werd gegenereerd. Meestal waren deze tijdelijke waarden grote negatieve getallen.

Nieuw gedrag

Vanaf 3.0 slaat EF Core de tijdelijke sleutelwaarde op als onderdeel van de traceringsgegevens van de entiteit en blijft de sleuteleigenschap zelf ongewijzigd.

Waarom

Deze wijziging is aangebracht om te voorkomen dat tijdelijke sleutelwaarden per ongeluk permanent worden wanneer een entiteit die eerder door een DbContext exemplaar is bijgehouden, wordt verplaatst naar een ander DbContext exemplaar.

Maatregelen

Toepassingen die primaire sleutelwaarden toewijzen aan refererende sleutels om koppelingen tussen entiteiten te vormen, zijn mogelijk afhankelijk van het oude gedrag als de primaire sleutels worden opgeslagen en behoren tot entiteiten met de status Added. Dit kan worden vermeden door:

  • Niet het gebruik van door de winkel gegenereerde sleutels.
  • Navigatie-eigenschappen instellen om relaties te vormen in plaats van het instellen van waarden voor buitenlandse sleutels.
  • Haal de werkelijke tijdelijke sleutelwaarden op uit de traceringsgegevens van de entiteit. context.Entry(blog).Property(e => e.Id).CurrentValue retourneert bijvoorbeeld de tijdelijke waarde, ook al is blog.Id zelf niet ingesteld.

DetectChanges erkent door de winkel gegenereerde sleutelwaarden

-traceringsprobleem #14616

Oud gedrag

Vóór EF Core 3.0 wordt een niet-bijgehouden entiteit die door DetectChanges is gevonden, bijgehouden in de status Added en ingevoegd als een nieuwe rij wanneer SaveChanges wordt aangeroepen.

Nieuw gedrag

Vanaf EF Core 3.0 wordt, als een entiteit gegenereerde sleutelwaarden gebruikt en er een sleutelwaarde is ingesteld, de entiteit in de status Modified bijgehouden. Dit betekent dat een rij voor de entiteit wordt verondersteld te bestaan en dat deze wordt bijgewerkt wanneer SaveChanges wordt aangeroepen. Als de sleutelwaarde niet is ingesteld of als het entiteitstype geen gegenereerde sleutels gebruikt, wordt de nieuwe entiteit nog steeds bijgehouden als Added zoals in eerdere versies.

Waarom

Deze wijziging is aangebracht om het eenvoudiger en consistenter te maken om te werken met losgekoppelde entiteitsgrafieken tijdens het gebruik van door de store gegenereerde sleutels.

Maatregelen

Deze wijziging kan een toepassing breken als een entiteitstype is geconfigureerd voor het gebruik van gegenereerde sleutels, maar sleutelwaarden expliciet zijn ingesteld voor nieuwe exemplaren. De oplossing is om de sleuteleigenschappen expliciet te configureren om gegenereerde waarden niet te gebruiken. Bijvoorbeeld met de fluent-API:

modelBuilder
    .Entity<Blog>()
    .Property(e => e.Id)
    .ValueGeneratedNever();

Of met gegevensaantekeningen:

[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id { get; set; }

Trapsgewijs verwijderen gebeurt nu standaard onmiddellijk

-traceringsprobleem #10114

Oud gedrag

Vóór 3.0 paste EF Core trapsgewijze acties toe (afhankelijke entiteiten verwijderen wanneer een vereiste principal wordt verwijderd of wanneer de relatie met een vereiste principal wordt verbroken), niet voordat SaveChanges werd aangeroepen.

Nieuw gedrag

Vanaf 3.0 past EF Core trapsgewijze acties toe zodra de triggervoorwaarde wordt gedetecteerd. Als u bijvoorbeeld context.Remove() aanroept om een principal-entiteit te verwijderen, worden alle bijgehouden vereiste afhankelijke afhankelijken ook onmiddellijk ingesteld op Deleted.

Waarom

Deze wijziging is aangebracht om de ervaring voor gegevensbinding en controlescenario's te verbeteren, waarbij het belangrijk is te begrijpen welke entiteiten worden verwijderd voordatSaveChanges wordt aangeroepen.

Maatregelen

Het vorige gedrag kan worden hersteld via instellingen op context.ChangeTracker. Bijvoorbeeld:

context.ChangeTracker.CascadeDeleteTiming = CascadeTiming.OnSaveChanges;
context.ChangeTracker.DeleteOrphansTiming = CascadeTiming.OnSaveChanges;

probleem met bijhouden #18022

Oud gedrag

Voordat 3.0 verzamelingen-navigaties gretig werden geladen via Include operators, werden er meerdere query's uitgevoerd op een relationele database, één voor elk gerelateerd entiteitstype.

Nieuw gedrag

Vanaf 3.0 genereert EF Core één query met JOI's voor relationele databases.

Waarom

Het uitgeven van meerdere query's voor het implementeren van één LINQ-query heeft talloze problemen veroorzaakt, waaronder negatieve prestaties als meerdere databaserondes nodig waren, en problemen met de coherentie van gegevens, omdat elke query een andere status van de database kon observeren.

Maatregelen

Hoewel dit technisch gezien geen belangrijke wijziging is, kan dit een aanzienlijk effect hebben op de prestaties van toepassingen wanneer één query een groot aantal Include operator bevat voor verzamelingsnavigatie. Zie deze opmerking voor meer informatie en voor het herschrijven van query's op een efficiëntere manier.

**

DeleteBehavior.Restrict heeft schonere semantiek

probleem met bijhouden #12661-

Oud gedrag

Vóór 3.0, maakte DeleteBehavior.Restrict externe sleutels in de database met Restrict- semantiek, maar veranderde ook de interne fixup op een onverwachte manier.

Nieuw gedrag

Vanaf 3.0 zorgt DeleteBehavior.Restrict ervoor dat refererende sleutels worden aangemaakt met Restrict semantiek, dat wil zeggen, geen cascades; uitwerpen bij schending van beperkingen, zonder invloed te hebben op interne EF-fixup.

Waarom

Deze wijziging is aangebracht om de ervaring voor het gebruik van DeleteBehavior op een intuïtieve manier te verbeteren, zonder onverwachte bijwerkingen.

Oplossingen

Het vorige gedrag kan worden hersteld met behulp van DeleteBehavior.ClientNoAction.

Querytypen worden samengevoegd met entiteitstypen

Probleem #14194 volgen

Oud gedrag

Vóór EF Core 3.0 waren querytypen een manier om query's uit te voeren op gegevens die geen primaire sleutel op een gestructureerde manier definiëren. Dat wil zeggen, werd er een querytype gebruikt voor het toewijzen van entiteitstypen zonder sleutels (waarschijnlijker vanuit een weergave, maar mogelijk uit een tabel), terwijl er een regulier entiteitstype werd gebruikt wanneer er een sleutel beschikbaar was (waarschijnlijker uit een tabel, maar mogelijk vanuit een weergave).

Nieuw gedrag

Een querytype wordt nu alleen een entiteitstype zonder primaire sleutel. Sleutelloze entiteitstypen hebben dezelfde functionaliteit als querytypen in eerdere versies.

Waarom

Deze wijziging is aangebracht om de verwarring rond het doel van querytypen te verminderen. Ze zijn met name sleutelloze entiteitstypen en ze zijn inherent alleen-lezen vanwege dit, maar ze mogen niet alleen worden gebruikt omdat een entiteitstype alleen-lezen moet zijn. Op dezelfde manier worden ze vaak toegewezen aan weergaven, maar dit komt alleen omdat weergaven vaak geen sleutels definiëren.

Oplossingen

De volgende onderdelen van de API zijn nu verouderd:

  • ModelBuilder.Query<>(): in plaats daarvan moet ModelBuilder.Entity<>().HasNoKey() worden aangeroepen om een entiteitstype te markeren als geen sleutels. Dit zou nog steeds niet volgens de conventie worden geconfigureerd om onjuiste configuratie te voorkomen wanneer een primaire sleutel wordt verwacht, maar niet overeenkomt met de conventie.
  • DbQuery<> : in plaats daarvan moet DbSet<> worden gebruikt.
  • DbContext.Query<>() : in plaats daarvan moet DbContext.Set<>() worden gebruikt.
  • IQueryTypeConfiguration<TQuery> : in plaats daarvan moet IEntityTypeConfiguration<TEntity> worden gebruikt.

Notitie

Vanwege een probleem in 3.x bij het uitvoeren van query's op sleutelloze entiteiten waarop alle eigenschappen zijn ingesteld op null wordt een null geretourneerd in plaats van een entiteit, als dit probleem ook van toepassing is op uw scenario, voegt u logica toe om null in resultaten te verwerken.

nl-NL: Configuratie-API voor relaties van 'owned types' is gewijzigd

Probleem bijhouden #12444TrackingProbleem #9148TrackingProbleem #14153

Oud gedrag

Vóór EF Core 3.0 werd de configuratie van de eigendomrelatie onmiddellijk na de OwnsOne- of OwnsMany-aanroep uitgevoerd.

Nieuw gedrag

Vanaf EF Core 3.0 is er een fluent API beschikbaar om een navigatie-eigenschap naar de eigenaar te configureren met behulp van WithOwner(). Bijvoorbeeld:

modelBuilder.Entity<Order>.OwnsOne(e => e.Details).WithOwner(e => e.Order);

De configuratie met betrekking tot de relatie tussen eigenaar en eigendom moet nu worden gekoppeld na WithOwner() vergelijkbaar met de configuratie van andere relaties. Hoewel de configuratie voor het eigendomstype zelf nog steeds gekoppeld wordt na OwnsOne()/OwnsMany(). Bijvoorbeeld:

modelBuilder.Entity<Order>.OwnsOne(e => e.Details, eb =>
    {
        eb.WithOwner()
            .HasForeignKey(e => e.AlternateId)
            .HasConstraintName("FK_OrderDetails");

        eb.ToTable("OrderDetails");
        eb.HasKey(e => e.AlternateId);
        eb.HasIndex(e => e.Id);

        eb.HasOne(e => e.Customer).WithOne();

        eb.HasData(
            new OrderDetails
            {
                AlternateId = 1,
                Id = -1
            });
    });

Als u Entity(), HasOne()of Set() aanroept met een doelobject van het type eigendom, wordt er voortaan een uitzondering gegenereerd.

Waarom

Deze wijziging is aangebracht om een helderder scheiding te maken tussen het configureren van het type zelf en de relatie tot het eigendomstype. Dit verwijdert op zijn beurt dubbelzinnigheid en verwarring rond methoden zoals HasForeignKey.

Maatregelen

Wijzig de configuratie van eigendomsrelaties om de nieuwe API-interface te gebruiken, zoals wordt weergegeven in het bovenstaande voorbeeld.

Afhankelijke entiteiten die de tabel delen met de principal zijn nu optioneel

Volgprobleem #9005

Oud gedrag

Houd rekening met het volgende model:

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public OrderDetails Details { get; set; }
}

public class OrderDetails
{
    public int Id { get; set; }
    public string ShippingAddress { get; set; }
}

Vóór EF Core 3.0, als OrderDetails eigendom is van Order of expliciet is toegewezen aan dezelfde tabel, was er altijd een OrderDetails exemplaar vereist bij het toevoegen van een nieuwe Order.

Nieuw gedrag

Vanaf 3.0 staat EF Core toe een Order zonder een OrderDetails toe te voegen en kent alle OrderDetails eigenschappen, behalve de primaire sleutel, toe aan null-kolommen. Bij het uitvoeren van een query op EF Core wordt OrderDetails ingesteld op null als een van de vereiste eigenschappen geen waarde heeft of als er geen vereiste eigenschappen naast de primaire sleutel zijn en alle eigenschappen zijn null.

Oplossingen

Als uw model een tabelafhankelijke relatie heeft met alle kolommen als optioneel, maar de navigatie die ernaar wijst niet null hoeft te zijn, moet de toepassing worden aangepast om gevallen af te handelen wanneer de navigatie nullis. Als dit niet mogelijk is, moet een vereiste eigenschap worden toegevoegd aan het entiteitstype of moet ten minste één eigenschap een niet-null waarde hebben die eraan is toegewezen.

Alle entiteiten die een tabel met een gelijktijdigheidstokenkolom delen, moeten deze toewijzen aan een eigenschap

Volgen van issue #14154

Oud gedrag

Houd rekening met het volgende model:

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public byte[] Version { get; set; }
    public OrderDetails Details { get; set; }
}

public class OrderDetails
{
    public int Id { get; set; }
    public string ShippingAddress { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Order>()
        .Property(o => o.Version).IsRowVersion().HasColumnName("Version");
}

Voor EF Core 3.0, als OrderDetails eigendom is van Order of expliciet aan dezelfde tabel is toegewezen, zal het bijwerken van alleen OrderDetails de Version-waarde op de client niet bijwerken, en zal de volgende update mislukken.

Nieuw gedrag

Vanaf 3.0 wordt de nieuwe Version waarde door EF Core doorgegeven aan Order als deze eigenaar is van OrderDetails. Anders wordt er een uitzondering gegenereerd tijdens modelvalidatie.

Waarom

Deze wijziging is aangebracht om een verouderde gelijktijdigheidstokenwaarde te voorkomen wanneer slechts één van de entiteiten die aan dezelfde tabel zijn toegewezen, wordt bijgewerkt.

Risicobeperkingen

Alle entiteiten die de tabel delen, moeten een eigenschap opnemen die is toegewezen aan de kolom met gelijktijdigheidstokens. Het is mogelijk dat u er een maakt met de schaduwstatus:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<OrderDetails>()
        .Property<byte[]>("Version").IsRowVersion().HasColumnName("Version");
}

Entiteiten in eigendom kunnen niet worden opgevraagd zonder de eigenaar met behulp van een traceringsquery

trackingprobleem #18876

Oud gedrag

Vóór EF Core 3.0 konden gebonden entiteiten worden opgevraagd als elke andere navigatie.

context.People.Select(p => p.Address);

Nieuw gedrag

Vanaf 3.0 genereert EF Core een traceringsquery die een entiteit in eigendom zonder de eigenaar projecteert.

Waarom

Entiteiten in eigendom kunnen niet worden gemanipuleerd zonder de eigenaar, dus in het overgrote deel van de gevallen waarin ze op deze manier worden opgevraagd, is dit een fout.

Maatregelen

Als de entiteit in eigendom moet worden bijgehouden om later te worden gewijzigd, moet de eigenaar worden opgenomen in de query.

Voeg anders een AsNoTracking()-aanroep toe:

context.People.Select(p => p.Address).AsNoTracking();

Overgenomen eigenschappen van niet-toegewezen typen worden nu toegewezen aan één kolom voor alle afgeleide typen

Volg probleem #13998

Oud gedrag

Houd rekening met het volgende model:

public abstract class EntityBase
{
    public int Id { get; set; }
}

public abstract class OrderBase : EntityBase
{
    public int ShippingAddress { get; set; }
}

public class BulkOrder : OrderBase
{
}

public class Order : OrderBase
{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Ignore<OrderBase>();
    modelBuilder.Entity<EntityBase>();
    modelBuilder.Entity<BulkOrder>();
    modelBuilder.Entity<Order>();
}

Vóór EF Core 3.0 wordt de eigenschap ShippingAddress standaard toegewezen aan afzonderlijke kolommen voor BulkOrder en Order.

Nieuw gedrag

Vanaf 3.0 maakt EF Core slechts één kolom voor ShippingAddress.

Waarom

Het oude gedrag was onverwacht.

Maatregelen

De eigenschap kan nog steeds expliciet worden toegewezen aan afzonderlijke kolommen van de afgeleide typen:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Ignore<OrderBase>();
    modelBuilder.Entity<EntityBase>();
    modelBuilder.Entity<BulkOrder>()
        .Property(o => o.ShippingAddress).HasColumnName("BulkShippingAddress");
    modelBuilder.Entity<Order>()
        .Property(o => o.ShippingAddress).HasColumnName("ShippingAddress");
}

De conventie van de vreemde-sleuteleigenschap komt niet meer overeen met de naam van de hoofdeigenschap.

Volgprobleem #13274

Oud gedrag

Houd rekening met het volgende model:

public class Customer
{
    public int CustomerId { get; set; }
    public ICollection<Order> Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
}

Vóór EF Core 3.0 werd de eigenschap CustomerId per conventie gebruikt voor de vreemde sleutel. Als Order echter een eigendomstype is, zou dit ook betekenen dat CustomerId de primaire sleutel wordt, en dat is meestal niet wat verwacht wordt.

Nieuw gedrag

Vanaf 3.0 probeert EF Core standaard geen eigenschappen te gebruiken voor foreign keys als deze dezelfde naam hebben als de principal-eigenschap. De naam van het principal-type, samengevoegd met de naam van de principal-eigenschap, en de navigatienaam, samengevoegd met de patronen van principal-eigenschapsnamen, komen nog steeds overeen. Bijvoorbeeld:

public class Customer
{
    public int Id { get; set; }
    public ICollection<Order> Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
}
public class Customer
{
    public int Id { get; set; }
    public ICollection<Order> Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public int BuyerId { get; set; }
    public Customer Buyer { get; set; }
}

Waarom

Deze wijziging is aangebracht om te voorkomen dat er per ongeluk een primaire sleuteleigenschap wordt gedefinieerd voor het type eigendom.

Oplossingen

Als de eigenschap bedoeld was om de vreemde sleutel te zijn en dus onderdeel van de primaire sleutel, configureert u deze expliciet als zodanig.

Databaseverbinding is nu gesloten als deze niet meer wordt gebruikt voordat de TransactionScope is voltooid

Volgprobleem #14218

Oud gedrag

Voordat EF Core 3.0, als de context de verbinding binnen een TransactionScopeopent, blijft de verbinding geopend terwijl de huidige TransactionScope actief is.

using (new TransactionScope())
{
    using (AdventureWorks context = new AdventureWorks())
    {
        context.ProductCategories.Add(new ProductCategory());
        await context.SaveChangesAsync();

        // Old behavior: Connection is still open at this point

        var categories = await context.ProductCategories().ToListAsync();
    }
}

Nieuw gedrag

Vanaf versie 3.0 sluit EF Core de verbinding zodra het klaar is met het gebruik ervan.

Waarom

Met deze wijziging kunt u meerdere contexten in dezelfde TransactionScopegebruiken. Het nieuwe gedrag komt ook overeen met EF6.

Maatregelen

Als de verbinding open moet blijven staan expliciete aanroep naar OpenConnection() zorgt ervoor dat EF Core deze niet voortijdig sluit:

using (new TransactionScope())
{
    using (AdventureWorks context = new AdventureWorks())
    {
        await context.Database.OpenConnectionAsync();
        context.ProductCategories.Add(new ProductCategory());
        await context.SaveChangesAsync();

        var categories = await context.ProductCategories().ToListAsync();
        await context.Database.CloseConnectionAsync();
    }
}

Elke eigenschap maakt gebruik van onafhankelijke in-memory generatie van integersleutels

Volgen van probleem #6872

Oud gedrag

Vóór EF Core 3.0 werd één gedeelde waarde-generator gebruikt voor alle geheugensleuteleigenschappen met gehele getallen.

Nieuw gedrag

Vanaf EF Core 3.0 krijgt elke eigenschap voor gehele getallen een eigen waardegenerator wanneer de database in het geheugen wordt gebruikt. Als de database wordt verwijderd, wordt het genereren van sleutels voor alle tabellen opnieuw ingesteld.

Waarom

Deze wijziging is aangebracht om het genereren van sleutels in het geheugen nauwkeuriger af te stemmen op het genereren van echte databasesleutels en om de mogelijkheid om tests van elkaar te isoleren bij gebruik van de in-memory database te verbeteren.

Maatregelen

Dit kan een toepassing verbreken die afhankelijk is van specifieke waarden in het geheugen die moeten worden ingesteld. Overweeg in plaats daarvan niet te vertrouwen op specifieke sleutelwaarden of om bij te werken om overeen te komen met het nieuwe gedrag.

Ondersteunende velden worden standaard toegepast

Tracking Issue #12430

Oud gedrag

Vóór 3.0, zelfs als het achterliggende veld voor een eigenschap bekend was, las en schreef EF Core de eigenschapswaarde nog steeds standaard met behulp van de getter- en settermethoden van de eigenschap. De uitzondering hierop was het uitvoeren van query's, waarbij het back-upveld direct zou worden ingesteld als dit bekend is.

Nieuw gedrag

Beginnend met EF Core 3.0, als het backingveld voor een eigenschap bekend is, zal EF Core die eigenschap altijd lezen en schrijven met behulp van het backingveld. Dit kan een toepassingsonderbreking veroorzaken als de toepassing afhankelijk is van aanvullend gedrag dat is gecodeerd in de getter- of settermethoden.

Waarom

Deze wijziging is aangebracht om te voorkomen dat EF Core per ongeluk bedrijfslogica activeert bij het uitvoeren van databasebewerkingen met betrekking tot de entiteiten.

Maatregelen

Het gedrag vóór 3.0 kan worden hersteld via de configuratie van de eigenschapstoegangsmodus op ModelBuilder. Bijvoorbeeld:

modelBuilder.UsePropertyAccessMode(PropertyAccessMode.PreferFieldDuringConstruction);

Gooien als er meerdere compatibele backingvelden worden gevonden

probleem bijhouden #12523

Oud gedrag

Vóór EF Core 3.0, als meerdere velden overeenkomen met de regels voor het vinden van het backingveld van een eigenschap, wordt één veld gekozen op basis van een bepaalde prioriteitsvolgorde. Dit kan ertoe leiden dat het verkeerde veld wordt gebruikt in dubbelzinnige gevallen.

Nieuw gedrag

Vanaf EF Core 3.0 wordt er een uitzondering gegenereerd als meerdere velden overeenkomen met dezelfde eigenschap.

Waarom

Deze wijziging is aangebracht om te voorkomen dat het ene veld stilletjes boven een ander veld wordt verkozen wanneer slechts één veld correct kan zijn.

Oplossingen

Eigenschappen met onduidelijke achterliggende velden moeten expliciet het te gebruiken veld opgegeven krijgen. Gebruik bijvoorbeeld de fluent-API:

modelBuilder
    .Entity<Blog>()
    .Property(e => e.Id)
    .HasField("_id");

Eigenschapsnamen die alleen voor velden gelden, moeten overeenkomen met de veldnaam.

Oud gedrag

Vóór EF Core 3.0 kan een eigenschap worden opgegeven met een tekenreekswaarde en als er geen eigenschap met die naam is gevonden op het .NET-type, probeert EF Core deze te koppelen aan een veld met behulp van conventieregels.

private class Blog
{
    private int _id;
    public string Name { get; set; }
}
modelBuilder
    .Entity<Blog>()
    .Property("Id");

Nieuw gedrag

Vanaf EF Core 3.0 moet een veldeigenschap exact overeenkomen met de veldnaam.

modelBuilder
    .Entity<Blog>()
    .Property("_id");

Waarom

Deze wijziging is aangebracht om te voorkomen dat hetzelfde veld wordt gebruikt voor twee eigenschappen die op dezelfde manier worden genoemd. Ook worden de overeenkomende regels voor alleen-veldeigenschappen hetzelfde als voor eigenschappen die zijn toegewezen aan CLR-eigenschappen.

Oplossingen

Veldeigen eigenschappen moeten dezelfde naam hebben als het veld waaraan ze zijn toegewezen. In een toekomstige release van EF Core na 3.0 zijn we van plan om expliciet een veldnaam te configureren die verschilt van de eigenschapsnaam (zie probleem #15307):

modelBuilder
    .Entity<Blog>()
    .Property("Id")
    .HasField("_id");

AddDbContext/AddDbContextPool roept AddLogging en AddMemoryCache niet meer aan

Te volgen probleem #14756

Oud gedrag

Vóór EF Core 3.0 registreert het aanroepen van AddDbContext of AddDbContextPool ook services voor logboekregistratie en geheugencaching bij DI via aanroepen naar AddLogging- en AddMemoryCache-.

Nieuw gedrag

Vanaf EF Core 3.0 registreren AddDbContext en AddDbContextPool deze services niet meer bij Dependency Injection (DI).

Waarom

EF Core 3.0 vereist niet dat deze services zich in de DI-container van de toepassing bevinden. Als ILoggerFactory echter is geregistreerd in de DI-container van de toepassing, wordt deze nog steeds gebruikt door EF Core.

Maatregelen

Als uw toepassing deze services nodig heeft, registreert u deze expliciet bij de DI-container met behulp van AddLogging- of AddMemoryCache-.

AddEntityFramework* voegt IMemoryCache toe met een groottelimiet

Volg probleem #12905

Oud gedrag

Voor EF Core 3.0 zou het aanroepen van AddEntityFramework*-methoden ook geheugencachingservices bij DI registreren zonder een groottelimiet.

Nieuw gedrag

Vanaf EF Core 3.0 registreert AddEntityFramework* een IMemoryCache-service met een groottelimiet. Als andere services die later worden toegevoegd, afhankelijk zijn van IMemoryCache, kunnen ze snel de standaardlimiet bereiken die uitzonderingen of verminderde prestaties veroorzaken.

Waarom

Het gebruik van IMemoryCache zonder limiet kan leiden tot onbeheerd geheugengebruik als er een fout optreedt in de cachelogica van query's of als de query's dynamisch worden gegenereerd. Als u een standaardlimiet hebt, wordt een mogelijke DoS-aanval beperkt.

Oplossingen

In de meeste gevallen is het aanroepen van AddEntityFramework* niet nodig als AddDbContext of AddDbContextPool ook wordt aangeroepen. Daarom is de beste oplossing om de AddEntityFramework* aanroep te verwijderen.

Als uw toepassing deze services nodig heeft, moet u vooraf een IMemoryCache-implementatie registreren bij de DI-container met behulp van AddMemoryCache.

DbContext.Entry voert nu een lokale DetectChanges uit

probleem bijhouden #13552

Oud gedrag

Voor EF Core 3.0 zou het aanroepen van DbContext.Entry ervoor zorgen dat wijzigingen voor alle bijgehouden entiteiten werden gedetecteerd. Dit zorgde ervoor dat de toestand die in de EntityEntry werd weergegeven, overeenkwam met de up-to-datum.

Nieuw gedrag

Vanaf EF Core 3.0 probeert het aanroepen van DbContext.Entry nu alleen wijzigingen in de opgegeven entiteit en eventuele bijgehouden principal-entiteiten die hieraan zijn gerelateerd, te detecteren. Dit betekent dat wijzigingen elders mogelijk niet zijn gedetecteerd door deze methode aan te roepen, wat gevolgen kan hebben voor de toepassingsstatus.

Houd er rekening mee dat als ChangeTracker.AutoDetectChangesEnabled is ingesteld op false, zelfs deze lokale wijzigingsdetectie wordt uitgeschakeld.

Andere methoden die wijzigingsdetectie veroorzaken, bijvoorbeeld ChangeTracker.Entries en SaveChanges, veroorzaken nog steeds een volledige DetectChanges van alle bijgehouden entiteiten.

Waarom

Deze wijziging is aangebracht om de standaardprestaties van het gebruik van context.Entryte verbeteren.

Beperkingen

Roep ChangeTracker.DetectChanges() expliciet aan voordat u Entry belt om ervoor te zorgen dat het gedrag van vóór 3.0 wordt gegarandeerd.

Tekenreeks- en bytematrixsleutels worden niet standaard door de client gegenereerd

-traceringsprobleem #14617

Oud gedrag

Vóór EF Core 3.0 kunnen string en byte[] sleuteleigenschappen worden gebruikt zonder expliciet een niet-null-waarde in te stellen. In dat geval wordt de sleutelwaarde op de client gegenereerd als een GUID, geserialiseerd tot bytes voor byte[].

Nieuw gedrag

Vanaf EF Core 3.0 wordt een uitzondering gegenereerd die aangeeft dat er geen sleutelwaarde is ingesteld.

Waarom

Deze wijziging is aangebracht omdat door de client gegenereerde string/byte[] waarden doorgaans niet nuttig zijn en het standaardgedrag maakte het moeilijk om op een gemeenschappelijke manier redeneren over gegenereerde sleutelwaarden.

Maatregelen

Het gedrag vóór 3.0 kan worden verkregen door expliciet op te geven dat de sleuteleigenschappen gegenereerde waarden moeten gebruiken als er geen andere niet-null-waarde is ingesteld. Bijvoorbeeld met de fluent-API:

modelBuilder
    .Entity<Blog>()
    .Property(e => e.Id)
    .ValueGeneratedOnAdd();

Of met gegevensaantekeningen:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }

ILoggerFactory is nu een 'scoped service' (een in omvang beperkte dienst)

Volgprobleem #14698

Oud gedrag

Voor EF Core 3.0 werd ILoggerFactory als singletonservice geregistreerd.

Nieuw gedrag

Vanaf EF Core 3.0 wordt ILoggerFactory nu geregistreerd als gescopeerd.

Waarom

Deze wijziging is aangebracht om de koppeling van een logger met een DbContext exemplaar mogelijk te maken, waardoor andere functionaliteit mogelijk is en sommige gevallen van pathologisch gedrag, zoals een explosie van interne serviceproviders, worden verwijderd.

Mitigerende maatregelen

Deze wijziging mag geen invloed hebben op toepassingscode, tenzij deze aangepaste services registreert en gebruikt op de interne EF Core-serviceprovider. Dit is niet gebruikelijk. In deze gevallen werken de meeste dingen nog steeds, maar elke singleton-service die afhankelijk is van ILoggerFactory moet worden gewijzigd om de ILoggerFactory op een andere manier te verkrijgen.

Als u dergelijke situaties ondervindt, dient u een probleem in op de EF Core GitHub GitHub-probleemtracker om ons te laten weten hoe u ILoggerFactory gebruikt, zodat we beter begrijpen hoe we dit in de toekomst niet opnieuw kunnen verbreken.

Luie laadproxies gaan er niet langer van uit dat navigatie-eigenschappen volledig zijn geladen

Volgkwestie #12780

Oud gedrag

Vóór EF Core 3.0 was er, zodra een DbContext was disposeerd, geen manier om te weten of een bepaalde navigatie-eigenschap op een entiteit verkregen uit die context volledig was geladen of niet. Proxy's gaan er in plaats daarvan van uit dat een verwijzingsnavigatie wordt geladen als deze een niet-null-waarde heeft en dat een verzamelingsnavigatie wordt geladen als deze niet leeg is. In dergelijke gevallen zou een poging om te lazy-loaden een no-opzijn.

Nieuw gedrag

Vanaf EF Core 3.0 houden proxy's bij of er al dan niet een navigatie-eigenschap wordt geladen. Dit betekent dat een poging om toegang te krijgen tot een navigatie-eigenschap die wordt geladen nadat de context is verwijderd, altijd een no-opis, zelfs wanneer de geladen navigatie leeg of null is. Als u echter probeert toegang te krijgen tot een navigatie-eigenschap die niet is geladen, wordt er een uitzondering gegenereerd als de context wordt verwijderd, zelfs als de navigatie-eigenschap een niet-lege verzameling is. Als deze situatie zich voordoet, betekent dit dat de toepassingscode probeert lazyloading op een ongeldig tijdstip te gebruiken en dat de toepassing moet worden gewijzigd om dit niet te doen.

Waarom

Deze wijziging is aangebracht om het gedrag consistent en correct te maken bij het lazy-loaden van een opgeheven DbContext-exemplaar.

Maatregelen

Werk de toepassingscode bij om niet te proberen lazy-loading te gebruiken met een afgesloten context, of configureer dit als een no-op zoals beschreven in de foutmelding.

Overmatige creatie van interne serviceproviders is nu standaard een fout

probleem bijhouden #10236

Oud gedrag

Vóór EF Core 3.0, werd een waarschuwing vastgelegd voor een toepassing die een pathologisch aantal interne service-providers creëerde.

Nieuw gedrag

Vanaf EF Core 3.0 wordt deze waarschuwing nu beschouwd als een fout en treedt er een uitzondering op.

Waarom

Deze wijziging is aangebracht om betere toepassingscode te stimuleren door deze pathologische case expliciet zichtbaar te maken.

Maatregelen

De meest geschikte handelswijze bij het optreden van deze fout is het begrijpen van de hoofdoorzaak en stoppen met het creëren van zoveel interne serviceproviders. De fout kan echter opnieuw worden geconverteerd naar een waarschuwing (of genegeerd) via de configuratie op de DbContextOptionsBuilder. Bijvoorbeeld:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .ConfigureWarnings(w => w.Log(CoreEventId.ManyServiceProvidersCreatedWarning));
}

Nieuw gedrag voor HasOne/HasMany aangeroepen met één tekenreeks

probleem bijhouden #9171

Oud gedrag

Vóór EF Core 3.0 werd code die HasOne of HasMany aanroept met één tekenreeks op een verwarrende manier geïnterpreteerd. Bijvoorbeeld:

modelBuilder.Entity<Samurai>().HasOne("Entrance").WithOne();

De code lijkt verband te houden tussen Samurai en een ander entiteitstype met behulp van de mogelijk privé Entrance-navigatie-eigenschap.

In werkelijkheid probeert deze code een relatie te maken met een bepaald entiteitstype met de naam Entrance zonder navigatie-eigenschap.

Nieuw gedrag

Vanaf EF Core 3.0 werkt de bovenstaande code nu zoals het eerder had moeten doen.

Waarom

Het oude gedrag was erg verwarrend, vooral bij het lezen van de configuratiecode en het zoeken naar fouten.

Maatregelen

Hierdoor worden alleen toepassingen verbroken die expliciet relaties configureren met behulp van tekenreeksen voor typenamen en zonder expliciet de navigatie-eigenschap op te geven. Dit is niet gebruikelijk. Het vorige gedrag kan worden verkregen door null expliciet als de naam van de navigatie-eigenschap door te geven. Bijvoorbeeld:

modelBuilder.Entity<Samurai>().HasOne("Some.Entity.Type.Name", null).WithOne();

Het retourtype voor verschillende asynchrone methoden is gewijzigd van Taak in ValueTask

Probleem volgen #15184

Oud gedrag

De volgende asynchrone methoden hebben eerder een Task<T>geretourneerd:

  • DbContext.FindAsync()
  • DbSet.FindAsync()
  • DbContext.AddAsync()
  • DbSet.AddAsync()
  • ValueGenerator.NextValueAsync() (en afgeleide klassen)

Nieuw gedrag

De bovengenoemde methoden retourneren nu een ValueTask<T> over dezelfde T als voorheen.

Waarom

Deze wijziging vermindert het aantal heap-toewijzingen dat wordt gemaakt bij het aanroepen van deze methoden, waardoor de algemene prestaties worden verbeterd.

Maatregelen

Toepassingen die alleen wachten op de bovenstaande API's hoeven alleen opnieuw te worden gecompileerd. Er zijn geen bronwijzigingen nodig. Een complexer gebruik (bijvoorbeeld het doorgeven van de geretourneerde Task aan Task.WhenAny()) vereist doorgaans dat de geretourneerde ValueTask<T> worden geconverteerd naar een Task<T> door er AsTask() op aan te roepen. Houd er rekening mee dat hiermee de toewijzingsvermindering wordt weggenomen die deze wijziging brengt.

De annotatie Relational:TypeMapping is nu gewoon TypeMapping

probleem bijhouden #9913

Oud gedrag

De annotatienaam voor typetoewijzingsannotaties was 'Relational:TypeMapping'.

Nieuw gedrag

De naam van de aantekening voor typetoewijzingsaantekeningen is nu 'TypeMapping'.

Waarom

Typetoewijzingen worden nu gebruikt voor meer dan alleen relationele databaseproviders.

Beperkingsmaatregelen

Hierdoor worden alleen toepassingen onderbroken die direct toegang hebben tot de typekoppeling in de vorm van een aantekening, wat niet gebruikelijk is. De meest geschikte actie om te corrigeren, is om de API-interface te gebruiken voor toegang tot typemappingen in plaats van de annotatie rechtstreeks te gebruiken.

ToTable op een afgeleid type genereert een uitzondering

probleem bijhouden #11811

Oud gedrag

Vóór EF Core 3.0 zou een aanroep van ToTable() op een afgeleid type worden genegeerd, omdat de enige overnametoewijzingsstrategie TPH was, en dit daarin niet geldig is.

Nieuw gedrag

Vanaf EF Core 3.0, en ter voorbereiding op het toevoegen van ondersteuning voor TPT en TPC in een latere release, zal een aanroep van ToTable() op een afgeleid type nu een uitzondering genereren om onverwachte toewijzingswijzigingen in de toekomst te voorkomen.

Waarom

Momenteel is het niet geldig om een afgeleid type toe te wijzen aan een andere tabel. Deze wijziging voorkomt dat er in de toekomst fouten optreden wanneer het een geldige taak wordt.

Maatregelen

Verwijder alle pogingen om afgeleide typen toe te wijzen aan andere tabellen.

ForSqlServerHasIndex vervangen door HasIndex

probleem bijhouden #12366

Oud gedrag

Voor EF Core 3.0 bood ForSqlServerHasIndex().ForSqlServerInclude() een manier om kolommen te configureren die werden gebruikt met INCLUDE.

Nieuw gedrag

Vanaf EF Core 3.0 wordt het gebruik van Include op een index nu ondersteund op relationeel niveau. Gebruik HasIndex().ForSqlServerInclude().

Waarom

Deze wijziging is aangebracht om de API voor indexen samen te voegen met Include op één plaats voor alle databaseproviders.

Maatregelen

Gebruik de nieuwe API, zoals hierboven wordt weergegeven.

Wijzigingen in metagegevens-API

bijhouden van probleem #214

Nieuw gedrag

De volgende eigenschappen zijn geconverteerd naar extensiemethoden:

  • IEntityType.QueryFilter ->GetQueryFilter()
  • IEntityType.DefiningQuery ->GetDefiningQuery()
  • IProperty.IsShadowProperty ->IsShadowProperty()
  • IProperty.BeforeSaveBehavior ->GetBeforeSaveBehavior()
  • IProperty.AfterSaveBehavior ->GetAfterSaveBehavior()

Waarom

Deze wijziging vereenvoudigt de implementatie van bovengenoemde interfaces.

Maatregelen

Gebruik de nieuwe extensiemethoden.

Wijzigingen in de API voor providerspecifieke metagegevens

bijhouden van probleem #214

Nieuw gedrag

De providerspecifieke uitbreidingsmethoden worden afgevlakt:

  • IProperty.Relational().ColumnName ->IProperty.GetColumnName()
  • IEntityType.SqlServer().IsMemoryOptimized ->IEntityType.IsMemoryOptimized()
  • PropertyBuilder.UseSqlServerIdentityColumn() ->PropertyBuilder.UseIdentityColumn()

Waarom

Deze wijziging vereenvoudigt de implementatie van de bovengenoemde uitbreidingsmethoden.

Maatregelen

Gebruik de nieuwe extensiemethoden.

EF Core verzendt geen pragma meer voor SQLite FK-afdwinging

probleem bijhouden #12151

Oud gedrag

Vóór EF Core 3.0 zou EF Core PRAGMA foreign_keys = 1 verzenden wanneer een verbinding met SQLite wordt geopend.

Nieuw gedrag

Vanaf EF Core 3.0 verzendt EF Core geen PRAGMA foreign_keys = 1 meer wanneer een verbinding met SQLite wordt geopend.

Waarom

Deze wijziging is aangebracht omdat EF Core standaard gebruikmaakt van SQLitePCLRaw.bundle_e_sqlite3, wat op zijn beurt betekent dat FK-afdwinging standaard is ingeschakeld en niet expliciet hoeft te worden ingeschakeld telkens wanneer een verbinding wordt geopend.

Maatregelen

Vreemde sleutels worden standaard ingeschakeld in SQLitePCLRaw.bundle_e_sqlite3, dat standaard wordt gebruikt voor EF Core. In andere gevallen kunnen vreemde sleutels worden ingeschakeld door Foreign Keys=True op te geven in uw verbindingsreeks.

Microsoft.EntityFrameworkCore.Sqlite is nu afhankelijk van SQLitePCLRaw.bundle_e_sqlite3

Oud gedrag

Vóór EF Core 3.0 gebruikte EF Core SQLitePCLRaw.bundle_green.

Nieuw gedrag

Vanaf EF Core 3.0 maakt EF Core gebruik van SQLitePCLRaw.bundle_e_sqlite3.

Waarom

Deze wijziging is aangebracht zodat de versie van SQLite die wordt gebruikt op iOS consistent is met andere platforms.

Oplossingen

Als u de systeemeigen SQLite-versie in iOS wilt gebruiken, configureert u Microsoft.Data.Sqlite om een andere SQLitePCLRaw bundel te gebruiken.

Guid-waarden worden nu opgeslagen als TEKST op SQLite

probleem volgen #15078

Oud gedrag

Guid-waarden werden eerder opgeslagen als BLOB-waarden op SQLite.

Nieuw gedrag

Guid-waarden worden nu opgeslagen als TEKST.

Waarom

De binaire indeling van Guids is niet gestandaardiseerd. Door de waarden op te slaan als TEKST, is de database beter compatibel met andere technologieën.

Oplossingen

U kunt bestaande databases migreren naar de nieuwe indeling door SQL als volgt uit te voeren.

UPDATE MyTable
SET GuidColumn = hex(substr(GuidColumn, 4, 1)) ||
                 hex(substr(GuidColumn, 3, 1)) ||
                 hex(substr(GuidColumn, 2, 1)) ||
                 hex(substr(GuidColumn, 1, 1)) || '-' ||
                 hex(substr(GuidColumn, 6, 1)) ||
                 hex(substr(GuidColumn, 5, 1)) || '-' ||
                 hex(substr(GuidColumn, 8, 1)) ||
                 hex(substr(GuidColumn, 7, 1)) || '-' ||
                 hex(substr(GuidColumn, 9, 2)) || '-' ||
                 hex(substr(GuidColumn, 11, 6))
WHERE typeof(GuidColumn) == 'blob';

In EF Core kunt u ook het vorige gedrag blijven gebruiken door een waardeconversieprogramma voor deze eigenschappen te configureren.

modelBuilder
    .Entity<MyEntity>()
    .Property(e => e.GuidProperty)
    .HasConversion(
        g => g.ToByteArray(),
        b => new Guid(b));

Microsoft.Data.Sqlite kan guid-waarden lezen uit zowel BLOB- als TEKSTkolommen; Aangezien de standaardindeling voor parameters en constanten echter is gewijzigd, moet u waarschijnlijk actie ondernemen voor de meeste scenario's met Guids.

Tekenwaarden worden nu opgeslagen als TEKST op SQLite

bijhouden van probleem #15020

Oud gedrag

Tekenwaarden werden eerder opgeslagen als INTEGER-waarden op SQLite. Een tekenwaarde van A- is bijvoorbeeld opgeslagen als de gehele waarde 65.

Nieuw gedrag

Tekenwaarden worden nu opgeslagen als tekst.

Waarom

Het opslaan van de waarden als TEKST is natuurlijker en maakt de database compatibeler met andere technologieën.

Maatregelen

U kunt bestaande databases migreren naar de nieuwe indeling door SQL als volgt uit te voeren.

UPDATE MyTable
SET CharColumn = char(CharColumn)
WHERE typeof(CharColumn) = 'integer';

In EF Core kunt u ook het vorige gedrag blijven gebruiken door een waardeconversieprogramma voor deze eigenschappen te configureren.

modelBuilder
    .Entity<MyEntity>()
    .Property(e => e.CharProperty)
    .HasConversion(
        c => (long)c,
        i => (char)i);

Microsoft.Data.Sqlite kan ook tekenwaarden lezen uit kolommen GEHEEL GETAL en TEKST, dus voor bepaalde scenario's is mogelijk geen actie vereist.

Migratie-id's worden nu gegenereerd met behulp van de agenda van de invariante cultuur

Volgprobleem #12978

Oud gedrag

Migratie-id's zijn per ongeluk gegenereerd met behulp van de agenda van de huidige cultuur.

Nieuw gedrag

Migratie-id's worden nu altijd gegenereerd met behulp van de kalender van de invariante cultuur (Gregoriaanse).

Waarom

De volgorde van migraties is belangrijk bij het bijwerken van de database of het oplossen van samenvoegingsconflicten. Het gebruik van de invariante agenda voorkomt ordeproblemen die kunnen voortvloeien uit teamleden die verschillende systeemkalenders hebben.

Mitigerende maatregelen

Deze wijziging is van invloed op iedereen die een niet-Gregoriaanse kalender gebruikt waar het jaar groter is dan de Gregoriaanse kalender (zoals de Thaise boeddhistische kalender). Bestaande migratie-id's moeten worden bijgewerkt, zodat nieuwe migraties na bestaande migraties worden geordend.

De migratie-id vindt u in het kenmerk Migratie in de ontwerpbestanden van de migraties.

 [DbContext(typeof(MyDbContext))]
-[Migration("25620318122820_MyMigration")]
+[Migration("20190318122820_MyMigration")]
 partial class MyMigration
 {

De geschiedenistabel migraties moet ook worden bijgewerkt.

UPDATE __EFMigrationsHistory
SET MigrationId = CONCAT(LEFT(MigrationId, 4)  - 543, SUBSTRING(MigrationId, 4, 150))

UseRowNumberForPaging werd verwijderd

probleem bijhouden #16400

Oud gedrag

Vóór EF Core 3.0 kan UseRowNumberForPaging worden gebruikt om SQL te genereren voor paging die compatibel is met SQL Server 2008.

Nieuw gedrag

Vanaf EF Core 3.0 genereert EF alleen SQL voor paging die alleen compatibel is met latere SQL Server-versies.

Waarom

Deze wijziging wordt aangebracht omdat SQL Server 2008 geen ondersteund product meer is en het significant werk is om deze functie bij te werken zodat deze werkt met de querywijzigingen die in EF Core 3.0 zijn doorgevoerd.

Maatregelen

U wordt aangeraden bij te werken naar een nieuwere versie van SQL Server of een hoger compatibiliteitsniveau te gebruiken, zodat de gegenereerde SQL wordt ondersteund. Dat gezegd hebbende, als u dit niet kunt doen, geef dan een opmerking bij het traceringsticket met details. We kunnen deze beslissing opnieuw bekijken op basis van feedback.

Extensie-informatie/metagegevens zijn verwijderd uit IDbContextOptionsExtension

-traceringsprobleem #16119

Oud gedrag

IDbContextOptionsExtension bevat methoden voor het verstrekken van metagegevens over de extensie.

Nieuw gedrag

Deze methoden zijn verplaatst naar een nieuwe DbContextOptionsExtensionInfo abstracte basisklasse, die wordt geretourneerd vanuit een nieuwe eigenschap IDbContextOptionsExtension.Info.

Waarom

In de releases van 2.0 tot 3.0 moesten we deze methoden meerdere keren toevoegen of wijzigen. Als u ze uitsplitst in een nieuwe abstracte basisklasse, is het eenvoudiger om dit soort wijzigingen aan te brengen zonder bestaande extensies te verbreken.

Maatregelen

Werk extensies bij om het nieuwe patroon te volgen. Voorbeelden zijn te vinden in de vele implementaties van IDbContextOptionsExtension voor verschillende soorten extensies in de EF Core-broncode.

De naam van LogQueryPossibleExceptionWithAggregateOperator is gewijzigd

Volgen van probleem #10985

Veranderen

RelationalEventId.LogQueryPossibleExceptionWithAggregateOperator is gewijzigd in RelationalEventId.LogQueryPossibleExceptionWithAggregateOperatorWarning.

Waarom

Hiermee wordt de naamgeving van deze waarschuwings gebeurtenis uitgelijnd met alle andere waarschuwingsevenementen.

Maatregelen

Gebruik de nieuwe naam. (Houd er rekening mee dat het gebeurtenis-id-nummer niet is gewijzigd.)

API verduidelijken voor namen van foreign key beperkingen

probleem met bijhouden #10730

Oud gedrag

Vóór EF Core 3.0 werden foreign key-constraint-namen eenvoudigweg "de naam" genoemd. Bijvoorbeeld:

var constraintName = myForeignKey.Name;

Nieuw gedrag

Vanaf EF Core 3.0 worden namen van foreign key-beperkingen nu aangeduid als de "beperkingsnaam". Bijvoorbeeld:

var constraintName = myForeignKey.ConstraintName;

Waarom

Deze wijziging brengt consistentie in naamgeving in dit gebied en verduidelijkt ook dat dit de naam is van de beperking voor refererende sleutels, en niet de kolom- of eigenschapsnaam waarop de refererende sleutel is gedefinieerd.

Oplossingen

Gebruik de nieuwe naam.

IRelationalDatabaseCreator.HasTables/HasTablesAsync is openbaar gemaakt

probleem bijhouden #15997

Oud gedrag

Vóór EF Core 3.0 werden deze methoden beveiligd.

Nieuw gedrag

Vanaf EF Core 3.0 zijn deze methoden openbaar.

Waarom

Deze methoden worden door EF gebruikt om te bepalen of een database is gemaakt, maar leeg is. Dit kan ook nuttig zijn van buiten EF bij het bepalen of migraties al dan niet moeten worden toegepast.

Oplossingen

Wijzig de toegankelijkheid van eventueel overschrijvingen.

Microsoft.EntityFrameworkCore.Design is nu een DevelopmentDependency-pakket

probleem bijhouden #11506

Oud gedrag

Vóór EF Core 3.0 was Microsoft.EntityFrameworkCore.Design een gewoon NuGet-pakket waarvan naar de assembly kan worden verwezen door projecten die ervan afhankelijk waren.

Nieuw gedrag

Vanaf EF Core 3.0 is het een DevelopmentDependency-pakket. Dit betekent dat de afhankelijkheid niet transitief naar andere projecten wordt doorgegeven en dat u standaard niet meer naar de assembly kunt verwijzen.

Waarom

Dit pakket is alleen bedoeld om te worden gebruikt tijdens het ontwerp. Geïmplementeerde toepassingen mogen er niet naar verwijzen. Door het pakket als een DevelopmentDependency in te stellen, wordt deze aanbeveling versterkt.

Beperkende maatregelen

Als u naar dit pakket wilt verwijzen om het ontwerptijdgedrag van EF Core te overschrijven, kunt u metagegevens van packageReference-items in uw project bijwerken.

<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.0.0">
  <PrivateAssets>all</PrivateAssets>
  <!-- Remove IncludeAssets to allow compiling against the assembly -->
  <!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
</PackageReference>

Als het pakket transitief wordt verwezen via Microsoft.EntityFrameworkCore.Tools, moet u een expliciete PackageReference toevoegen aan het pakket om de metagegevens ervan te wijzigen. Een dergelijke expliciete verwijzing moet worden toegevoegd aan elk project waar de typen van het pakket nodig zijn.

SQLitePCL.raw bijgewerkt naar versie 2.0.0

Volgprobleem #14824

Oud gedrag

Microsoft.EntityFrameworkCore.Sqlite was eerder afhankelijk van versie 1.1.12 van SQLitePCL.raw.

Nieuw gedrag

We hebben ons pakket bijgewerkt zodat het afhankelijk is van versie 2.0.0.

Waarom

Versie 2.0.0 van SQLitePCL.raw is gericht op .NET Standard 2.0. Het was eerder gericht op .NET Standard 1.1, waarvoor een grote sluiting van transitieve pakketten moest worden uitgevoerd.

Oplossingen

SQLitePCL.raw versie 2.0.0 bevat enkele belangrijke wijzigingen. Zie de releaseopmerkingen van voor meer informatie.

NetTopologySuite bijgewerkt naar versie 2.0.0

bijhouden van probleem #14825

Oud gedrag

De ruimtelijke pakketten waren eerder afhankelijk van versie 1.15.1 van NetTopologySuite.

Nieuw gedrag

We hebben ons pakket bijgewerkt zodat het afhankelijk is van versie 2.0.0.

Waarom

Versie 2.0.0 van NetTopologySuite is bedoeld om verschillende bruikbaarheidsproblemen op te lossen die zijn opgetreden door EF Core-gebruikers.

Maatregelen

NetTopologySuite versie 2.0.0 bevat enkele belangrijke wijzigingen. Zie de releaseopmerkingen van voor meer informatie.

Microsoft.Data.SqlClient wordt gebruikt in plaats van System.Data.SqlClient

Probleem bijhouden #15636

Oud gedrag

Microsoft.EntityFrameworkCore.SqlServer was eerder afhankelijk van System.Data.SqlClient.

Nieuw gedrag

We hebben ons pakket bijgewerkt zodat het afhankelijk is van Microsoft.Data.SqlClient.

Waarom

Microsoft.Data.SqlClient is het vlaggenschipstuurprogramma voor gegevenstoegang voor SQL Server, en System.Data.SqlClient is niet langer de focus van ontwikkeling. Enkele belangrijke functies, zoals Always Encrypted, zijn alleen beschikbaar op Microsoft.Data.SqlClient.

Oplossingen

Als uw code rechtstreeks afhankelijk is van System.Data.SqlClient, moet u deze wijzigen om in plaats daarvan te verwijzen naar Microsoft.Data.SqlClient; omdat de twee pakketten een zeer hoge mate van API-compatibiliteit behouden, mag dit alleen een eenvoudige pakket- en naamruimtewijziging zijn.

Er moeten meerdere dubbelzinnige zelfverwijzende relaties worden geconfigureerd

trackingprobleem #13573

Oud gedrag

Een entiteitstype met meerdere zelfverwijzende unidirectionele navigatie-eigenschappen en overeenkomende FK's is onjuist geconfigureerd als één relatie. Bijvoorbeeld:

public class User
{
        public Guid Id { get; set; }
        public User CreatedBy { get; set; }
        public User UpdatedBy { get; set; }
        public Guid CreatedById { get; set; }
        public Guid? UpdatedById { get; set; }
}

Nieuw gedrag

Dit scenario wordt nu gedetecteerd in het bouwen van modellen en er wordt een uitzondering gegenereerd die aangeeft dat het model dubbelzinnig is.

Waarom

Het resulterende model is dubbelzinnig en is waarschijnlijk onjuist voor dit geval.

Maatregelen

Gebruik de volledige configuratie van de relatie. Bijvoorbeeld:

modelBuilder
     .Entity<User>()
     .HasOne(e => e.CreatedBy)
     .WithMany();

 modelBuilder
     .Entity<User>()
     .HasOne(e => e.UpdatedBy)
     .WithMany();

DbFunction.Schema dat null of een lege tekenreeks is, configureert deze in het standaardschema van het model

probleem bijhouden #12757

Oud gedrag

Een DbFunction geconfigureerd met schema als een lege tekenreeks is behandeld als ingebouwde functie zonder schema. Met de volgende code wordt bijvoorbeeld DatePart CLR-functie toegewezen aan DATEPART ingebouwde functie op SqlServer.

[DbFunction("DATEPART", Schema = "")]
public static int? DatePart(string datePartArg, DateTime? date) => throw new Exception();

Nieuw gedrag

Alle DbFunction-toewijzingen worden beschouwd als toegewezen aan door de gebruiker gedefinieerde functies. Daarom zou de lege tekenreekswaarde de functie in het standaardschema voor het model plaatsen. Dit kan het schema zijn dat expliciet is geconfigureerd via de fluent API modelBuilder.HasDefaultSchema() of anders via dbo.

Waarom

Voorheen was het leegmaken van een schema een manier om die functie te behandelen, maar die logica is alleen van toepassing op SqlServer, waarbij ingebouwde functies geen deel uitmaken van een schema.

Maatregelen

Configureer de vertaling van DbFunction handmatig om deze toe te wijzen aan een ingebouwde functie.

modelBuilder
    .HasDbFunction(typeof(MyContext).GetMethod(nameof(MyContext.DatePart)))
    .HasTranslation(args => SqlFunctionExpression.Create("DatePart", args, typeof(int?), null));

EF Core 3.0 richt zich op .NET Standard 2.1 in plaats van .NET Standard 2.0 Teruggedraaid

Volgprobleem #15498

EF Core 3.0 is gericht op .NET Standard 2.1. Dit is een belangrijke wijziging die .NET Framework-toepassingen uitsluit. EF Core 3.1 heeft dit teruggedraaid en richt zich opnieuw op .NET Standard 2.0.

queryuitvoering wordt vastgelegd op foutopsporingsniveau Teruggedraaid

probleem met bijhouden #14523

Deze wijziging is teruggedraaid omdat met de nieuwe configuratie in EF Core 3.0 het logboekniveau voor elke gebeurtenis kan worden opgegeven door de toepassing. Als u bijvoorbeeld de logboekregistratie van SQL wilt overschakelen naar Debug, configureert u expliciet het niveau in OnConfiguring of AddDbContext:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseSqlServer(connectionString)
        .ConfigureWarnings(c => c.Log((RelationalEventId.CommandExecuting, LogLevel.Debug)));