Kurz: Informace o pokročilých scénářích – ASP.NET MVC s EF Core
V předchozím kurzu jste implementovali dědičnost tabulky na hierarchii. V tomto kurzu se seznámíte s několika tématy, o které byste si měli být vědomi, pokud jdete nad rámec základů vývoje ASP.NET Core aplikací, které používají Entity Framework Core.
V tomto kurzu jste:
- Provádění nezpracovaných SQL dotazů
- Volání dotazu pro vrácení entit
- Volání dotazu pro vrácení dalších typů
- Volání aktualizačního dotazu
- Prozkoumání SQL dotazů
- Vytvoření abstraktní vrstvy
- Další informace o automatické detekci změn
- Další informace o EF Core kódu a plánech vývoje
- Informace o použití dynamického linqu ke zjednodušení kódu
Požadavky
Provádění nezpracovaných SQL dotazů
Jednou z výhod používání Entity Framework je, že se vyhnete příliš blízkému vázání kódu na konkrétní metodu ukládání dat. Dělá to tak, že SQL dotazy a příkazy, což vám také umožní, abyste je museli psát sami. Existují však mimořádné scénáře, kdy potřebujete spustit konkrétní SQL dotazy, které jste vytvořili ručně. V těchto scénářích rozhraní API Entity Framework Code First metody, které vám umožní SQL příkazy přímo do databáze. Ve windows 1.0 EF Core následující možnosti:
Pro
DbSet.FromSqldotazy, které vracejí typy entit, použijte metodu . Vrácené objekty musí být typu očekávaného objektem a jsou automaticky sledovány kontextem databáze, pokud sledováníDbSetnevypnout.Pro příkazy
Database.ExecuteSqlCommandbez dotazu použijte .
Pokud potřebujete spustit dotaz, který vrátí typy, které nejsou entitami, můžete použít příkaz ADO.NET s připojením k databázi poskytovaném EF. Vrácená data nesleduje kontext databáze, i když tuto metodu použijete k načtení typů entit.
Jak je vždy pravdivé při spouštění SQL ve webové aplikaci, je nutné provést opatření k ochraně webu před útoky SQL útoky. Jedním ze způsobů, jak to provést, je použít parametrizované dotazy, abyste se ujistili, že řetězce odeslané webovou stránkou nelze interpretovat jako SQL příkazy. V tomto kurzu použijete parametrizované dotazy při integraci uživatelského vstupu do dotazu.
Volání dotazu pro vrácení entit
Třída DbSet<TEntity> poskytuje metodu , kterou můžete použít ke spuštění dotazu, který vrací entitu typu TEntity . Pokud chcete vidět, jak to funguje, změníte kód v Details metodě kontroleru oddělení.
V souboru DepartmentsController.cs v metodě nahraďte kód, který načte oddělení voláním metody, jak je znázorněno v Details následujícím FromSql zvýrazněném kódu:
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
string query = "SELECT * FROM Department WHERE DepartmentID = {0}";
var department = await _context.Departments
.FromSql(query, id)
.Include(d => d.Administrator)
.AsNoTracking()
.FirstOrDefaultAsync();
if (department == null)
{
return NotFound();
}
return View(department);
}
Pokud chcete ověřit, že nový kód funguje správně, vyberte kartu Oddělení a pak podrobnosti pro jedno z oddělení.

Volání dotazu pro vrácení dalších typů
Dříve jste vytvořili tabulku statistik studentů pro stránku O aplikaci, která ukazovala počet studentů pro každé datum registrace. Získali jste data ze sady entit Students ( ) a pomocí LINQ jste výsledky _context.Students promítli do seznamu objektů modelu EnrollmentDateGroup zobrazení. Předpokládejme, že chcete napsat SQL místo LINQ. K tomu je potřeba spustit dotaz SQL, který vrátí něco jiného než objekty entity. V EF Core 1.0 je jedním ze způsobů, jak to udělat, napsat ADO.NET kódu a získat připojení k databázi z EF.
V Home souboru Controller.cs nahraďte About metodu následujícím kódem:
public async Task<ActionResult> About()
{
List<EnrollmentDateGroup> groups = new List<EnrollmentDateGroup>();
var conn = _context.Database.GetDbConnection();
try
{
await conn.OpenAsync();
using (var command = conn.CreateCommand())
{
string query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
+ "FROM Person "
+ "WHERE Discriminator = 'Student' "
+ "GROUP BY EnrollmentDate";
command.CommandText = query;
DbDataReader reader = await command.ExecuteReaderAsync();
if (reader.HasRows)
{
while (await reader.ReadAsync())
{
var row = new EnrollmentDateGroup { EnrollmentDate = reader.GetDateTime(0), StudentCount = reader.GetInt32(1) };
groups.Add(row);
}
}
reader.Dispose();
}
}
finally
{
conn.Close();
}
return View(groups);
}
Přidejte příkaz using:
using System.Data.Common;
Spusťte aplikaci a přejděte na stránku O aplikaci. Zobrazí stejná data jako předtím.

Volání aktualizačního dotazu
Předpokládejme, že správci Contoso University chtějí provádět globální změny v databázi, například změnit počet kreditů pro každý kurz. Pokud má univerzita velký počet kurzů, bylo by neefektivní je načíst jako entity a změnit je jednotlivě. V této části implementujete webovou stránku, která uživateli umožní určit faktor, podle kterého se má změnit počet kreditů pro všechny kurzy, a tuto změnu provedete spuštěním příkazu SQL UPDATE. Webová stránka bude vypadat jako na následujícím obrázku:

V souboru CoursesController.cs přidejte metody UpdateCourseCredits pro HttpGet a HttpPost:
public IActionResult UpdateCourseCredits()
{
return View();
}
[HttpPost]
public async Task<IActionResult> UpdateCourseCredits(int? multiplier)
{
if (multiplier != null)
{
ViewData["RowsAffected"] =
await _context.Database.ExecuteSqlCommandAsync(
"UPDATE Course SET Credits = Credits * {0}",
parameters: multiplier);
}
return View();
}
Když kontroler zpracuje požadavek HttpGet, v se nic nevrátilo a zobrazení zobrazí prázdné textové pole a tlačítko pro odeslání, jak je znázorněno ViewData["RowsAffected"] na předchozím obrázku.
Po kliknutí na tlačítko Aktualizovat se volá metoda HttpPost a násobitel má hodnotu zadanou do textového pole. Kód pak spustí soubor SQL, který aktualizuje kurzy a vrátí počet ovlivněných řádků do zobrazení v ViewData . Když zobrazení získá RowsAffected hodnotu, zobrazí počet aktualizovaných řádků.
V Průzkumník řešení klikněte pravým tlačítkem na složku Views/Courses a potom klikněte na Add > New Item (Přidat novou položku).
V dialogovém okně Přidat novou položku klikněte na ASP.NET Core v Razor části Nainstalováno v levém podokně, klikněte na View (Zobrazit) a na název nového zobrazení UpdateCourseCredits.cshtml.
V souboru Views/Courses/UpdateCourseCredits.cshtml nahraďte kód šablony následujícím kódem:
@{
ViewBag.Title = "UpdateCourseCredits";
}
<h2>Update Course Credits</h2>
@if (ViewData["RowsAffected"] == null)
{
<form asp-action="UpdateCourseCredits">
<div class="form-actions no-color">
<p>
Enter a number to multiply every course's credits by: @Html.TextBox("multiplier")
</p>
<p>
<input type="submit" value="Update" class="btn btn-default" />
</p>
</div>
</form>
}
@if (ViewData["RowsAffected"] != null)
{
<p>
Number of rows updated: @ViewData["RowsAffected"]
</p>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
Spusťte metodu tak, že vyberete kartu Courses a na konec adresy URL v adresní řádku prohlížeče přidáte UpdateCourseCredits "/UpdateCourseCredits" (například http://localhost:5813/Courses/UpdateCourseCredits ). Do textového pole zadejte číslo:

Klikněte na Aktualizovat. Zobrazí se počet ovlivněných řádků:

Kliknutím na Zpět do seznamu zobrazíte seznam kurzů s upraveným počtem kreditů.
Všimněte si, že produkční kód zajistí, aby aktualizace vždy vedlo k platným datům. Zde zobrazený zjednodušený kód by mohl vynásobit počet kreditů tak, aby výsledkem byla čísla větší než 5. (Vlastnost Credits má [Range(0, 5)] atribut.) Dotaz na aktualizaci by fungoval, ale neplatná data by mohla způsobit neočekávané výsledky v jiných částech systému, které předpokládají, že počet kreditů je 5 nebo méně.
Další informace o nezpracovaných dotazech SQL naleznete v tématu Raw SQL Queries.
Prozkoumání SQL dotazů
Někdy je užitečné vidět skutečné dotazy, SQL se odesílaly do databáze. Funkce integrovaného protokolování pro ASP.NET Core automaticky používá EF Core k zápisu protokolů, které obsahují SQL dotazů a aktualizací. V této části se zobrazí několik příkladů protokolování SQL dat.
Otevřete soubor StudentsController.cs a v Details metodě nastavte zarážku na if (student == null) příkaz .
Spusťte aplikaci v režimu ladění a přejděte na stránku Podrobnosti pro studenta.
Přejděte do okna Výstup s výstupem ladění a zobrazí se dotaz:
Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (56ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30']
SELECT TOP(2) [s].[ID], [s].[Discriminator], [s].[FirstName], [s].[LastName], [s].[EnrollmentDate]
FROM [Person] AS [s]
WHERE ([s].[Discriminator] = N'Student') AND ([s].[ID] = @__id_0)
ORDER BY [s].[ID]
Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (122ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30']
SELECT [s.Enrollments].[EnrollmentID], [s.Enrollments].[CourseID], [s.Enrollments].[Grade], [s.Enrollments].[StudentID], [e.Course].[CourseID], [e.Course].[Credits], [e.Course].[DepartmentID], [e.Course].[Title]
FROM [Enrollment] AS [s.Enrollments]
INNER JOIN [Course] AS [e.Course] ON [s.Enrollments].[CourseID] = [e.Course].[CourseID]
INNER JOIN (
SELECT TOP(1) [s0].[ID]
FROM [Person] AS [s0]
WHERE ([s0].[Discriminator] = N'Student') AND ([s0].[ID] = @__id_0)
ORDER BY [s0].[ID]
) AS [t] ON [s.Enrollments].[StudentID] = [t].[ID]
ORDER BY [t].[ID]
Všimněte si něčeho, co vás může překvapit: SQL vybere z tabulky Person až 2 řádky ( TOP(2) ). Metoda SingleOrDefaultAsync se na serveru nevyřeší na 1 řádek. Důvod:
- Pokud dotaz vrátí více řádků, vrátí metoda hodnotu null.
- Pokud chcete zjistit, jestli by dotaz vrátil více řádků, musí EF zkontrolovat, jestli vrátí alespoň 2 řádky.
Všimněte si, že k získání výstupu protokolování v okně Výstup nemusíte používat režim ladění a zastavit se na zarážce. Je to jen pohodlný způsob, jak zastavit protokolování v bodě, kdy se chcete podívat na výstup. Pokud to neudáte, protokolování bude pokračovat a budete se muset posunout zpět, abyste našli části, které vás zajímají.
Vytvoření abstraktní vrstvy
Mnoho vývojářů píše kód pro implementaci úložiště a jednotek pracovních vzorů jako obálky kolem kódu, který funguje s Entity Framework. Účelem těchto vzorů je vytvořit abstraktní vrstvu mezi vrstvou přístupu k datům a vrstvou obchodní logiky aplikace. Implementace těchto vzorů může vaší aplikaci pomoct zabránit změnám v datovém úložiště a může usnadnit automatizované testování částí nebo vývoj řízený testy .TDD (Test-Driven Development). Psaní dalšího kódu pro implementaci těchto vzorů ale není vždy nejlepší volbou pro aplikace, které používají EF, z několika důvodů:
Třída kontextu EF sama o sobě využívá váš kód z kódu specifického pro úložiště dat.
Třída kontextu EF může fungovat jako třída unit-of-work pro aktualizace databáze, které používáte EF.
EF zahrnuje funkce pro implementaci TDD bez psaní kódu úložiště.
Informace o tom, jak implementovat úložiště a jednotky pracovních vzorů, najdete v Entity Framework 5 této série kurzů.
Entity Framework Core implementuje poskytovatele databáze v paměti, který lze použít k testování. Další informace najdete v tématu Testování pomocí InMemory.
Automatická detekce změn
Metoda Entity Framework určuje, jak se entita změnila (a které aktualizace je tedy potřeba odeslat do databáze) porovnáním aktuálních hodnot entity s původními hodnotami. Původní hodnoty se ukládají při dotazech na entitu nebo při jejich připojení. Některé z metod, které způsobují automatickou detekci změn, jsou následující:
DbContext.SaveChanges
DbContext.Entry
ChangeTracker.Entries
Pokud sledujete velký počet entit a často voláte jednu z těchto metod ve smyčce, můžete výrazně zlepšit výkon tím, že pomocí vlastnosti dočasně vypnete automatickou detekci ChangeTracker.AutoDetectChangesEnabled změn. Příklad:
_context.ChangeTracker.AutoDetectChangesEnabled = false;
EF Core zdrojový kód a vývojové plány
Zdroj Entity Framework Core je na https://github.com/dotnet/efcore adrese . Úložiště EF Core obsahuje noční buildy, sledování problémů, specifikace funkcí, poznámky ke schůzce návrhu a plán budoucího vývoje. Můžete zachycovat nebo hledat chyby a přispívat.
I když je zdrojový kód otevřený, Entity Framework Core je plně podporovaný jako produkt Microsoftu. Tým Microsoftu Entity Framework kontrolu nad přijetím příspěvků a testuje všechny změny kódu, aby se zajistila kvalita jednotlivých verzí.
Zpětná technika z existující databáze
Pokud chcete zpětně zkonstruovat analýzu datového modelu, včetně tříd entit z existující databáze, použijte příkaz scaffold-dbcontext. Podívejte se na kurz Začínáme.
Zjednodušení kódu pomocí dynamického LINQ
Třetí kurz v této sérii ukazuje, jak napsat kód LINQ pomocí pevného kódování názvů sloupců v příkazu switch . Pokud máte na výběr ze dvou sloupců, funguje to dobře, ale pokud máte mnoho sloupců, může být kód podrobný. Pokud chcete tento problém vyřešit, můžete pomocí metody EF.Property zadat název vlastnosti jako řetězec. Pokud chcete tento přístup vyzkoušet, nahraďte Index metodu v StudentsController souboru následujícím kódem.
public async Task<IActionResult> Index(
string sortOrder,
string currentFilter,
string searchString,
int? pageNumber)
{
ViewData["CurrentSort"] = sortOrder;
ViewData["NameSortParm"] =
String.IsNullOrEmpty(sortOrder) ? "LastName_desc" : "";
ViewData["DateSortParm"] =
sortOrder == "EnrollmentDate" ? "EnrollmentDate_desc" : "EnrollmentDate";
if (searchString != null)
{
pageNumber = 1;
}
else
{
searchString = currentFilter;
}
ViewData["CurrentFilter"] = searchString;
var students = from s in _context.Students
select s;
if (!String.IsNullOrEmpty(searchString))
{
students = students.Where(s => s.LastName.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}
if (string.IsNullOrEmpty(sortOrder))
{
sortOrder = "LastName";
}
bool descending = false;
if (sortOrder.EndsWith("_desc"))
{
sortOrder = sortOrder.Substring(0, sortOrder.Length - 5);
descending = true;
}
if (descending)
{
students = students.OrderByDescending(e => EF.Property<object>(e, sortOrder));
}
else
{
students = students.OrderBy(e => EF.Property<object>(e, sortOrder));
}
int pageSize = 3;
return View(await PaginatedList<Student>.CreateAsync(students.AsNoTracking(),
pageNumber ?? 1, pageSize));
}
Poděkování
V tomto kurzu napsali Tom Dykstra a Rick Anderson @RickAndMSFT (Twitter). Rowan Miller, Vega a další členové týmu společnosti Entity Framework vám pomohli s recenzemi kódu a pomohli ladit problémy, které se při psaní kódu pro tyto kurzy odhodlány. John Parente a Paul Goldman pracovali na aktualizaci kurzu pro ASP.NET Core 2.2.
Odstraňování běžných chyb
ContosoUniversity.dll používaný jiným procesem
Chybová zpráva:
Nelze otevřít soubor ...bin\Debug\netcoreapp1.0\ContosoUniversity.dll pro zápis – Proces nemůže získat přístup k souboru ...\bin\Debug\netcoreapp1.0\ContosoUniversity.dll, protože ho používá jiný proces.
Řešení:
Zastavte lokalitu v IIS Express. Přejděte na hlavní Windows systému, vyhledejte IIS Express klikněte pravým tlačítkem na jeho ikonu, vyberte web Contoso University a pak klikněte na Stop Site (Zastavit web).
Generování migrace bez kódu v metodách Nahoru a Dolů
Možná příčina:
Příkazy ROZHRANÍ příkazového řádku EF CLI nezav blízkosti a uložení souborů kódu automaticky neukují. Pokud při spuštění příkazu máte neuložené změny, EF změny migrations add nenajde.
Řešení:
Spusťte příkaz migrations remove , uložte změny kódu a spusťte příkaz migrations add znovu.
Chyby při spouštění aktualizace databáze
Při provádění změn schématu v databázi, která obsahuje existující data, je možné získat další chyby. Pokud dojde k chybám migrace, které nemůžete vyřešit, můžete změnit název databáze v připojovacím řetězci nebo databázi odstranit. V případě nové databáze nejsou k dispozici žádná data k migraci a je mnohem pravděpodobnější, že se příkaz update-database dokončí bez chyb.
Nejjednodušším přístupem je přejmenovat databázi v appsettings.json nástroji . Při příštím spuštění database update se vytvoří nová databáze.
Pokud chcete odstranit databázi v SSOX, klikněte pravým tlačítkem na databázi, klikněte na Odstranit a potom v dialogovém okně Odstranit databázi vyberte Zavřít existující připojení a klikněte na OK.
Pokud chcete databázi odstranit pomocí rozhraní příkazového řádku, spusťte database drop příkaz rozhraní příkazového řádku:
dotnet ef database drop
Chyba při SQL Server instance
Chybová zpráva:
Při navazování připojení k SQL Serveru došlo k chybě související se sítí nebo konkrétní instancí. Server se nenašel nebo nebyl dostupný. Ověřte správnost názvu instance a jestli je SQL Server nakonfigurovaný tak, aby povoloval vzdálená připojení. (poskytovatel: SQL síťová rozhraní, chyba: 26 – Chyba při hledání zadaného serveru nebo instance)
Řešení:
Zkontrolujte připojovací řetězec. Pokud jste ručně odstranili databázový soubor, změňte název databáze ve stavebním řetězci tak, aby začal znovu s novou databází.
Získání kódu
Stáhněte nebo zobrazte dokončenou aplikaci.
Další zdroje informací
Další informace o EF Core najdete v Entity Framework Core dokumentaci. K dispozici je také kniha: Entity Framework Core v akci.
Informace o tom, jak nasadit webovou aplikaci, najdete v tématu Hostování a nasazení ASP.NET Core .
Informace o dalších tématech souvisejících s ASP.NET Core MVC, jako je ověřování a autorizace, najdete v tématu Úvod do ASP.NET Core .
Další kroky
V tomto kurzu jste:
- Provedení nezpracovaných SQL dotazů
- Volání dotazu pro vrácení entit
- Volání dotazu pro vracení dalších typů
- Volání aktualizačního dotazu
- Prozkoumali jste SQL dotazy.
- Vytvořili jste abstraktní vrstvu.
- Dozvěděli jste se o automatické detekci změn.
- Informace o EF Core kódu a plánech vývoje
- Naučili jste se používat dynamický LINQ ke zjednodušení kódu.
Tím se dokončí tato série kurzů o používání Entity Framework Core v ASP.NET Core MVC. Tato série pracovala s novou databází. Alternativou je zpětná technika modelu z existující databáze.