Megosztás a következőn keresztül:


Oktatóanyag: Tudnivalók a speciális forgatókönyvekről – ASP.NET MVC EF Core

Az előző oktatóanyagban a hierarchiánkénti táblaöröklést implementálta. Ez az oktatóanyag számos olyan témakört mutat be, amelyekkel érdemes tisztában lenni, ha túllép az Entity Framework Core-t használó ASP.NET Core-webalkalmazások fejlesztésének alapjaion.

Ebben az oktatóanyagban ön:

  • Nyers SQL-lekérdezések végrehajtása
  • Lekérdezés indítása entitások visszaadására
  • Különböző típusok visszaadásához futtasson lekérdezést
  • Frissítési lekérdezés meghívása
  • SQL-lekérdezések vizsgálata
  • Absztrakciós réteg létrehozása
  • Tudnivalók az automatikus változásészlelésről
  • További információ EF Core forráskódról és fejlesztési tervekről
  • Ismerje meg, hogyan egyszerűsítheti le a kódokat a dinamikus LINQ használatával

Prerequisites

Nyers SQL-lekérdezések végrehajtása

Az Entity Framework használatának egyik előnye, hogy elkerüli, hogy a kód túlságosan szorosan kötődjön egy adott adattárolási módszerhez. Ezt úgy teszi, hogy SQL-lekérdezéseket és parancsokat hoz létre Önnek, ami szintén megszabadít attól, hogy saját maga kelljen írnia őket. Vannak azonban kivételes helyzetek, amikor manuálisan létrehozott sql-lekérdezéseket kell futtatnia. Ezekben a forgatókönyvekben az Entity Framework Code First API olyan metódusokat tartalmaz, amelyekkel közvetlenül az adatbázisba továbbíthat SQL-parancsokat. Az 1.0-s EF Core a következő lehetőségek közül választhat:

  • Az entitástípusokat visszaadó lekérdezésekhez használja a DbSet.FromSql metódust. A visszaadott objektumoknak az DbSet objektum által várt típusúnak kell lenniük, és az adatbázis-környezet automatikusan nyomon követi őket, hacsak nem kikapcsolni.

  • Használja a Database.ExecuteSqlCommand a nem lekérdezési parancsokhoz.

Ha olyan lekérdezést kell futtatnia, amely nem entitástípusokat ad vissza, használhatja ADO.NET az EF által biztosított adatbázis-kapcsolattal. A visszaadott adatokat az adatbázis-környezet nem követi nyomon, még akkor sem, ha ezzel a módszerrel kéri le az entitástípusokat.

Ahogy az mindig igaz, amikor SQL-parancsokat hajt végre egy webalkalmazásban, óvintézkedéseket kell tennie, hogy megvédje a webhelyet az SQL-injektálási támadásoktól. Ennek egyik módja a paraméteres lekérdezések használata annak érdekében, hogy a weblap által küldött sztringek ne értelmezhetők SQL-parancsokként. Ebben az oktatóanyagban paraméteres lekérdezéseket fog használni, amikor a felhasználói bemenetet egy lekérdezésbe integrálja.

Lekérdezés indítása entitások visszaadására

A DbSet<TEntity> osztály olyan metódust biztosít, amellyel olyan lekérdezést hajthat végre, amely egy TEntitytípusú entitást ad vissza. Ennek működéséhez módosítania kell a kódot a részlegvezérlő Details metódusában.

A DepartmentsController.csDetails metódusban cserélje le a részleget lekérő kódot egy FromSql metódushívásra, ahogyan az a következő kiemelt kódban látható:

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);
}

Ha ellenőrizni szeretné, hogy az új kód megfelelően működik-e, válassza a Részlegek lapot, majd Részletek az egyik részleghez.

Department Details

Különböző típusok visszaadásához futtasson lekérdezést

Előzőleg létrehozott egy diákstatisztikai táblázatot a Rólunk oldalhoz, amely a hallgatók számát mutatta minden beiratkozási dátumhoz. Az adatokat a Students entitáskészletből (_context.Students) szerezte be, és a LINQ használatával kivetítheti az eredményeket EnrollmentDateGroup modellobjektumok listájába. Tegyük fel, hogy magát az SQL-t szeretné írni a LINQ használata helyett. Ehhez olyan SQL-lekérdezést kell futtatnia, amely nem entitásobjektumokat ad vissza. Az EF Core 1.0-s verzióban ennek egyik módja, ha ADO.NET kódot ír, és az Entity Framework-től szerzi meg az adatbázis-kapcsolatot.

HomeController.cs-ban cserélje le a(z) About metódust a következő kódra:

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);
}

Adjon hozzá egy felhasználói utasítást:

using System.Data.Common;

Indítsa el az alkalmazást, és lépjen az "About" oldalra. Ugyanazokat az adatokat jeleníti meg, mint korábban.

About page

Frissítési lekérdezés meghívása

Tegyük fel, hogy a Contoso Egyetem rendszergazdái globális változásokat szeretnének végrehajtani az adatbázisban, például minden kurzus kreditszámának módosítását. Ha az egyetem számos kurzussal rendelkezik, nem lenne hatékony mindet entitásként lekérni, és egyenként módosítani. Ebben a szakaszban egy weblapot fog implementálni, amely lehetővé teszi a felhasználó számára, hogy meghatározzon egy tényezőt, amellyel az összes kurzus kreditjeinek számát módosíthatja, és a módosítást egy SQL UPDATE-utasítás végrehajtásával hajtja végre. A weblap a következő ábrához hasonlóan fog kinézni:

Tanfolyam kreditjeinek frissítése lap

A CoursesController.csadja hozzá az UpdateCourseCredits metódusokat a HttpGethez és a HttpPosthoz:

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();
}

Amikor a vezérlő feldolgoz egy HttpGet-kérést, a rendszer semmit sem ad vissza a ViewData["RowsAffected"], és a nézet egy üres szövegdobozt és egy küldési gombot jelenít meg az előző ábrán látható módon.

Amikor a Frissítés gombra kattint, a HttpPost metódus meghívásra kerül, és a szorzónak a szövegmezőben megadott érték kerül beállításra. A kód ezután végrehajtja az SQL-t, amely frissíti a tanfolyamokat, és visszaküldi az érintett sorok számát a ViewDatanézetbe. Amikor a nézet RowsAffected értéket kap, megjeleníti a frissített sorok számát.

A Megoldáskezelőbenkattintson a jobb gombbal a Nézetek/Tanfolyamok mappára, majd kattintson > Új elem hozzáadásaparancsra.

Az Új elem hozzáadása párbeszédpanelen kattintson a ASP.NET Core elemre a bal oldali panelen Telepített területen, kattintson a Razor Nézetelemre, és nevezze el az új nézetet UpdateCourseCredits.cshtml.

A(z) Views/Courses/UpdateCourseCredits.cshtml-ban cserélje le a sablonkódot a következő kódra:

@{
    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>

Futtassa a UpdateCourseCredits metódust a Tanfolyamok fülre kattintva, majd adja hozzá a "/UpdateCourseCredits" kifejezést az URL-cím végéhez a böngésző címsorában (például: http://localhost:5813/Courses/UpdateCourseCredits). Írjon be egy számot a szövegmezőbe:

Tanfolyam kreditjeinek frissítése lap

Click Update. Az érintett sorok száma:

Kurzus kreditjeinek oldal sorai érintettek

Kattintson a Vissza a Listára elemre a módosított kreditszámmal rendelkező kurzusok listájának megtekintéséhez.

Vegye figyelembe, hogy a production kód biztosítja, hogy a frissítések mindig érvényes adatokat eredményezzenek. Az itt bemutatott egyszerűsített kód megszorozhatja a kreditek számát ahhoz, hogy 5-nél nagyobb számokat eredményezjen. (A Credits tulajdonság [Range(0, 5)] attribútummal rendelkezik.) A frissítési lekérdezés működni fog, de az érvénytelen adatok váratlan eredményeket okozhatnak a rendszer más részeiben, amelyek feltételezik, hogy a kreditek száma 5 vagy kevesebb.

További információ a nyers SQL-lekérdezésekről: Nyers SQL-lekérdezések.

SQL-lekérdezések vizsgálata

Néha hasznos lehet látni az adatbázisba küldött tényleges SQL-lekérdezéseket. A ASP.NET Core beépített naplózási funkcióját a EF Core automatikusan használja az SQL-t tartalmazó naplók írására a lekérdezésekhez és frissítésekhez. Ebben a szakaszban néhány példát láthat az SQL-naplózásra.

Nyissa meg StudentsController.cs, és a Details metódusban állítson be töréspontot a if (student == null) utasításhoz.

Futtassa az alkalmazást hibakeresési módban, és nyissa meg egy tanuló Részletek lapját.

Lépjen a hibakeresési kimenetet megjelenítő Kimeneti ablakra, és megjelenik a lekérdezés:

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]

Itt valami meglepőt fog látni: az SQL legfeljebb 2 sort (TOP(2)) választ ki a Person táblából. A SingleOrDefaultAsync metódus nem képezhető le egy sorra a kiszolgálón. Here's why:

  • Ha a lekérdezés több sort ad vissza, a metódus null értéket ad vissza.
  • Annak megállapításához, hogy a lekérdezés több sort ad-e vissza, az EF-nek ellenőriznie kell, hogy legalább 2 értéket ad-e vissza.

Ne feledje, hogy nem kell hibakeresési módot használnia, és nem kell megállnia egy töréspontnál ahhoz, hogy naplózási kimenetet lásson a Kimeneti ablakban. Ezzel egyszerűen leállíthatja a naplózást azon a ponton, amikor meg szeretné tekinteni a kimenetet. Ha ezt nem teszi meg, a naplózás folytatódik, és vissza kell görgetnie, hogy megtalálja azokat a részeket, amelyek érdeklik.

Absztrakciós réteg létrehozása

Sok fejlesztő ír kódot az adattár és a munkaminták egysége burkolóként való implementálásához az Entity Framework használatával működő kód köré. Ezek a minták egy absztrakciós réteg létrehozására szolgálnak az adatelérési réteg és az alkalmazás üzleti logikai rétege között. Ezeknek a mintáknak a megvalósítása segíthet elszigetelni az alkalmazást az adattár változásaitól, és megkönnyítheti az automatizált egységtesztelést vagy a tesztalapú fejlesztést (TDD). Az EF-t használó alkalmazások esetében azonban nem mindig a legjobb választás, ha további kódokat írunk ezeknek a mintáknak a implementálásához:

  • Maga az EF környezeti osztály szigeteli a kódot az adattárspecifikus kódtól.

  • Az EF környezeti osztály munkaegységként működhet az EF használatával végzett adatbázis-frissítésekhez.

  • Az EF tartalmazza a TDD adattárkód írása nélküli implementálásának funkcióit.

Az adattár és a munkaminták egységeinek implementálásával kapcsolatos további információkért tekintse meg jelen oktatóanyag-sorozat Entity Framework 5-ös verziójának.

Az Entity Framework Core egy memórián belüli adatbázis-szolgáltatót implementál, amely tesztelésre használható. További információért lásd: Test with InMemory.

Automatikus változásészlelés

Az entitás-keretrendszer az entitás aktuális értékeinek az eredeti értékekkel való összehasonlításával határozza meg, hogyan változott az entitás (és ezért mely frissítéseket kell elküldeni az adatbázisba). Az eredeti értékek tárolása az entitás lekérdezésekor vagy csatolásakor történik. Az automatikus változásészlelést okozó módszerek némelyike a következő:

  • DbContext.SaveChanges

  • DbContext.Entry

  • ChangeTracker.Entries

Ha nagy számú entitást követ nyomon, és egy ciklusban többször is meghívja ezeket a metódusokat, jelentős teljesítménybeli javulást érhet el, ha ideiglenesen kikapcsolja az automatikus változásészlelést a ChangeTracker.AutoDetectChangesEnabled tulajdonság használatával. For example:

_context.ChangeTracker.AutoDetectChangesEnabled = false;

EF Core forráskód és fejlesztési tervek

Az Entity Framework Core forrása a https://github.com/dotnet/efcore. A EF Core adattár éjszakai buildeket, problémák nyomon követését, funkciók specifikációit, tervezési értekezlet jegyzeteit és a jövőbeli fejlesztésiütemtervét tartalmazza. Jelentheti vagy megkeresheti a hibákat, és közreműködhet.

Bár a forráskód nyitva van, az Entity Framework Core teljes mértékben támogatott Microsoft-termékként. A Microsoft Entity Framework csapata folyamatosan ellenőrzi, hogy mely hozzájárulásokat fogadják el, és teszteli az összes kódmódosítást az egyes kiadások minőségének biztosítása érdekében.

Visszafejtés meglévő adatbázisból

Ha egy meglévő adatbázisból származó entitásosztályokat tartalmazó adatmodellt szeretne visszafejteni, használja a scaffold-dbcontext parancsot. Tekintse meg az első lépéseket ismertető oktatóanyagot.

A dinamikus LINQ használata a kód leegyszerűsítéséhez

A sorozat harmadik oktatóanyaga bemutatja, hogyan írhat LINQ-kódot az oszlopnevek switch utasításban való kemény kódolásával. Ha két oszlop közül szeretne választani, ez jól működik, de ha sok oszlopot használ, a kód részletes lehet. A probléma megoldásához a EF.Property metódussal sztringként adhatja meg a tulajdonság nevét. A módszer kipróbálásához cserélje le a IndexStudentsController metódusát a következő kódra.

 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));
 }

Acknowledgments

Tom Dykstra és Rick Anderson (Twitter @RickAndMSFT) írta ezt az oktatóanyagot. Rowan Miller, Diego Vega és az Entity Framework csapatának más tagjai segítettek a kódértékelésekben, és segítettek a hibakeresésben, amelyek az oktatóanyagok kódjának megírása során merültek fel. John Parente és Paul Goldman dolgozott a ASP.NET Core 2.2 oktatóanyagának frissítésén.

Gyakori hibák elhárítása

Egy másik folyamat használja a(z) ContosoUniversity.dll-t.

Error message:

Nem lehet megnyitni a következőt: "... a bin\Debug\netcoreapp1.0\ContosoUniversity.dll' for writing -- 'The process cannot access the file '...\bin\Debug\netcoreapp1.0\ContosoUniversity.dll' fájlt, mert azt egy másik folyamat használja.

Solution:

Állítsa le a webhelyet az IIS Expressben. Lépjen a Windows rendszertálcára, keresse meg az IIS Expresst, és kattintson a jobb gombbal az ikonra, válassza a Contoso Egyetem webhelyét, majd kattintson a Webhely leállításaparancsra.

Kódmentes migrációs váz a Fel és Le metódusokban

Possible cause:

Az EF CLI-parancsok nem zárják be és mentik automatikusan a kódfájlokat. Ha a migrations add parancs futtatásakor nem mentett módosításokat, az EF nem találja a módosításokat.

Solution:

Futtassa a migrations remove parancsot, mentse a kód módosításait, és futtassa újra a migrations add parancsot.

Adatbázis-frissítés futtatásakor felmerülő hibák

Más hibák is előfordulhatnak, amikor sémamódosításokat hajt végre egy meglévő adatokat tartalmazó adatbázisban. Ha olyan áttelepítési hibákat kap, amit nem tud megoldani, módosíthatja az adatbázis nevét a kapcsolati sztringben, vagy törölheti az adatbázist. Új adatbázis esetén nincs migrálandó adat, és az update-database parancs sokkal valószínűbb, hogy hiba nélkül befejeződik.

A legegyszerűbb módszer az, ha átnevezed az adatbázist a appsettings.jsonhelyen. A database updatelegközelebbi futtatásakor egy új adatbázis jön létre.

Ha törölni szeretne egy adatbázist az SSOX-ban, kattintson a jobb gombbal az adatbázisra, kattintson a Törléselemre, majd az Adatbázis törlése párbeszédpanelen válassza a Meglévő kapcsolatok bezárása lehetőséget, majd kattintson OKgombra.

Ha törölni szeretne egy adatbázist a parancssori felület használatával, futtassa a database drop parancssori felület parancsot:

dotnet ef database drop

Hiba az SQL Server-példány helyének keresésekor

Error Message:

Hálózati vagy példányspecifikus hiba történt az SQL Server-kapcsolat létrehozásakor. A kiszolgáló nem található vagy nem érhető el. Ellenőrizze, hogy a példány neve helyes-e, és hogy az SQL Server a távoli kapcsolatok engedélyezésére van-e konfigurálva. (szolgáltató: SQL Hálózati felületek, hiba: 26 – Hiba a megadott kiszolgáló/példány helyének meghatározásakor)

Solution:

Ellenőrizze a kapcsolati sztringet. Ha manuálisan törölte az adatbázisfájlt, módosítsa az adatbázis nevét az építési sztringben, hogy egy új adatbázissal kezdjen újra.

A kód lekérése

Töltse le vagy tekintse meg a befejezett alkalmazást.

Additional resources

A EF Corekapcsolatos további információkért tekintse meg az Entity Framework Core dokumentációját. Egy könyv is elérhető: Entity Framework Core in Action.

A webalkalmazás üzembe helyezéséről további információt a ASP.NET Core tárhely és telepítéscímű részben talál.

Az ASP.NET Core MVC-vel kapcsolatos egyéb témakörökről, például a hitelesítésről és az engedélyezésről további információt ASP.NET Coreáttekintése című témakörben talál.

A megbízható, biztonságos, teljesíthető, tesztelhető és méretezhető ASP.NET Core-alkalmazás létrehozásával kapcsolatos útmutatásért tekintse meg Vállalati webalkalmazás-mintákcímű témakört. Rendelkezésre áll egy teljes gyártási minőségű webalkalmazás példa, amely a mintákat implementálja.

Next steps

Ebben az oktatóanyagban ön:

  • Nyers SQL-lekérdezések végrehajtása
  • Lekérdezés futtatása az entitások visszaadásához
  • Lekérdezés végrehajtása más típusok visszaadásához
  • Frissítési lekérdezés meghívása
  • Megvizsgált SQL-lekérdezések
  • Absztrakciós réteg létrehozása
  • Tudnivalók az automatikus változásészlelésről
  • EF Core forráskóddal és fejlesztési tervekkel kapcsolatos tudnivalók
  • Megtanulta, hogyan egyszerűsítheti le a kódokat a dinamikus LINQ használatával

Ez az oktatóanyag-sorozat az Entity Framework Core egy ASP.NET Core MVC-alkalmazásban való használatáról készült. Ez a sorozat egy új adatbázissal működött; Másik lehetőségként meglévő adatbázisból származó modell visszafejtése.