Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a szakasz ismerteti a kapcsolódó entitások EF-betöltésének néhány részletét, valamint a körkörös navigációs tulajdonságok kezelését a modellosztályokban. (Ez a szakasz háttérismereteket biztosít, és nem szükséges az oktatóanyag elvégzéséhez. Ha szeretné, ugorjon az 5. részre.)
Eager Loading és Lazy Loading
Ha relációs adatbázissal használja az EF-t, fontos tisztában lenni azzal, hogy az EF hogyan tölti be a kapcsolódó adatokat.
Hasznos az EF által generált SQL-lekérdezések megtekintése is. Az SQL nyomon követéséhez adja hozzá a következő kódsort a BookServiceContext konstruktorhoz:
public BookServiceContext() : base("name=BookServiceContext")
{
// New code:
this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
Ha GET kérést küld az /api/books szolgáltatásnak, az a JSON-t az alábbihoz hasonlóan adja vissza:
[
{
"BookId": 1,
"Title": "Pride and Prejudice",
"Year": 1813,
"Price": 9.99,
"Genre": "Comedy of manners",
"AuthorId": 1,
"Author": null
},
...
Láthatja, hogy a Szerző tulajdonság null értékű, annak ellenére, hogy a könyv érvényes AuthorId azonosítót tartalmaz. Ennek az az oka, hogy az EF nem tölti be a kapcsolódó Author entitásokat. Az SQL-lekérdezés nyomkövetési naplója a következőt erősíti meg:
SELECT
[Extent1].[BookId] AS [BookId],
[Extent1].[Title] AS [Title],
[Extent1].[Year] AS [Year],
[Extent1].[Price] AS [Price],
[Extent1].[Genre] AS [Genre],
[Extent1].[AuthorId] AS [AuthorId]
FROM [dbo].[Books] AS [Extent1]
A SELECT utasítás a Könyvek táblából származik, és nem hivatkozik a Szerző táblára.
Referenciaként itt található az osztály azon BooksController metódusa, amely a könyvek listáját adja vissza.
public IQueryable<Book> GetBooks()
{
return db.Books;
}
Lássuk, hogyan tudjuk visszaadni a Szerzőt a JSON-adatok részeként. Az Entity Frameworkben háromféleképpen tölthet be kapcsolódó adatokat: lelkes betöltést, lusta betöltést és explicit betöltést. Minden technikával vannak kompromisszumok, ezért fontos megérteni, hogyan működnek.
Lelkes betöltés
A lelkes betöltéssel az EF betölti a kapcsolódó entitásokat a kezdeti adatbázis-lekérdezés részeként. A gyors betöltéshez használja a System.Data.Entity.Include bővítménymetódust.
public IQueryable<Book> GetBooks()
{
return db.Books
// new code:
.Include(b => b.Author);
}
Ez azt jelzi, hogy az EF belefoglalja a Szerző adatokat a lekérdezésbe. Ha ezt a módosítást elvégezve futtatja az alkalmazást, a JSON-adatok a következőképpen néznek ki:
[
{
"BookId": 1,
"Title": "Pride and Prejudice",
"Year": 1813,
"Price": 9.99,
"Genre": "Comedy of manners",
"AuthorId": 1,
"Author": {
"AuthorId": 1,
"Name": "Jane Austen"
}
},
...
A nyomkövetési napló azt mutatja, hogy az EF végrehajtott egy összekapcsolást a Könyv és a Szerző táblákon.
SELECT
[Extent1].[BookId] AS [BookId],
[Extent1].[Title] AS [Title],
[Extent1].[Year] AS [Year],
[Extent1].[Price] AS [Price],
[Extent1].[Genre] AS [Genre],
[Extent1].[AuthorId] AS [AuthorId],
[Extent2].[AuthorId] AS [AuthorId1],
[Extent2].[Name] AS [Name]
FROM [dbo].[Books] AS [Extent1]
INNER JOIN [dbo].[Authors] AS [Extent2] ON [Extent1].[AuthorId] = [Extent2].[AuthorId]
lusta betöltés
Lusta betöltés esetén az EF automatikusan betölt egy kapcsolódó entitást, amikor az entitás navigációs tulajdonsága elérhetővé válik. A lusta betöltés engedélyezéséhez tegye virtuálissá a navigációs tulajdonságot. Például a Könyv osztályban:
public class Book
{
// (Other properties)
// Virtual navigation property
public virtual Author Author { get; set; }
}
Most vegye figyelembe a következő kódot:
var books = db.Books.ToList(); // Does not load authors
var author = books[0].Author; // Loads the author for books[0]
Amikor a lusta betöltés engedélyezve van, a Author tulajdonság elérésekor az books[0] EF lekérdezi az adatbázisból a szerző adatait.
A lusta betöltéshez több adatbázis-utazásra van szükség, mivel az EF minden alkalommal küld lekérdezést, amikor egy kapcsolódó entitást kér le. Általában le szeretné tiltani a lusta betöltést a szerializált objektumok esetében. A szerializálónak be kell olvasnia a modell összes tulajdonságát, ami elindítja a kapcsolódó entitások betöltését. Ilyenek például az SQL-lekérdezések, amikor az EF szerializálja a lusta betöltést engedélyező könyvek listáját. Láthatja, hogy az EF három külön lekérdezést készít a három szerző számára.
SELECT
[Extent1].[BookId] AS [BookId],
[Extent1].[Title] AS [Title],
[Extent1].[Year] AS [Year],
[Extent1].[Price] AS [Price],
[Extent1].[Genre] AS [Genre],
[Extent1].[AuthorId] AS [AuthorId]
FROM [dbo].[Books] AS [Extent1]
SELECT
[Extent1].[AuthorId] AS [AuthorId],
[Extent1].[Name] AS [Name]
FROM [dbo].[Authors] AS [Extent1]
WHERE [Extent1].[AuthorId] = @EntityKeyValue1
SELECT
[Extent1].[AuthorId] AS [AuthorId],
[Extent1].[Name] AS [Name]
FROM [dbo].[Authors] AS [Extent1]
WHERE [Extent1].[AuthorId] = @EntityKeyValue1
SELECT
[Extent1].[AuthorId] AS [AuthorId],
[Extent1].[Name] AS [Name]
FROM [dbo].[Authors] AS [Extent1]
WHERE [Extent1].[AuthorId] = @EntityKeyValue1
Még mindig vannak olyan esetek, amikor halasztott betöltést szeretne használni. A türelmetlen betöltéssel az EF nagyon összetett illesztést hozhat létre. Vagy előfordulhat, hogy az adatok egy kis részhalmazához kapcsolódó entitásokra van szüksége, és a lusta betöltés hatékonyabb lenne.
A szerializálási problémák elkerülésének egyik módja az adatátviteli objektumok (DTO-k) szerializálása entitásobjektumok helyett. Ezt a megközelítést a cikk későbbi részében mutatom be.
Explicit betöltés
Az explicit betöltés hasonló a lusta betöltéshez, azzal a kivételnel, hogy a kapcsolódó adatokat kifejezetten kódban kapja meg; ez nem történik meg automatikusan egy navigációs tulajdonság elérésekor. Az explicit betöltéssel jobban szabályozhatja, hogy mikor kell betölteni a kapcsolódó adatokat, de további kódot igényel. A explicit betöltéssel kapcsolatos további információkért lásd a Kapcsolódó entitások betöltése című témakört.
Navigációs tulajdonságok és körkörös hivatkozások
Amikor meghatároztam a Könyv és szerző modelleket, meghatároztam egy navigációs tulajdonságot az osztályban a Book Book-Author kapcsolathoz, de nem definiáltam navigációs tulajdonságot a másik irányba.
Mi történik, ha hozzáadja a megfelelő navigációs tulajdonságot az Author osztályhoz?
public class Author
{
public int AuthorId { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Book> Books { get; set; }
}
Ez sajnos problémát okoz a modellek szerializálása során. Ha betölti a kapcsolódó adatokat, az egy körkörös objektumdiagramot hoz létre.
Amikor a JSON- vagy XML-formázó megpróbálja szerializálni a gráfot, kivételt fog eredményezni. A két formázó különböző kivételüzeneteket küld. Íme egy példa a JSON-formátumolóra:
{
"Message": "An error has occurred.",
"ExceptionMessage": "The 'ObjectContent`1' type failed to serialize the response body for content type
'application/json; charset=utf-8'.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": null,
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Self referencing loop detected with type 'BookService.Models.Book'.
Path '[0].Author.Books'.",
"ExceptionType": "Newtonsoft.Json.JsonSerializationException",
"StackTrace": "..."
}
}
Itt található az XML-formázó:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>The 'ObjectContent`1' type failed to serialize the response body for content type
'application/xml; charset=utf-8'.</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace />
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>Object graph for type 'BookService.Models.Author' contains cycles and cannot be
serialized if reference tracking is disabled.</ExceptionMessage>
<ExceptionType>System.Runtime.Serialization.SerializationException</ExceptionType>
<StackTrace> ... </StackTrace>
</InnerException>
</Error>
Az egyik megoldás a DTO-k használata, amelyet a következő szakaszban ismertetek. Másik lehetőségként konfigurálhatja a JSON- és XML-formázókat a gráfciklusok kezeléséhez. További információ: Körkörös objektumhivatkozások kezelése.
Ebben az oktatóanyagban nincs szüksége a Author.Book navigációs tulajdonságra, így kihagyhatja.