Miroslav Holec

Software & Cloud Architect

miroslavholec.cz / blog / optimalizacni-testova-otazka-k-enity-framework

Optimalizační testová otázka k Entity Framework

Miroslav Holec

Miroslav Holec

Publikován 26. října 2015 , aktualizace: 29. března 2016

Tento článek je starší 18 měsíců a je proto možné, že popisuje postupy nebo technologie, které v uplynulé době mohly doznat výraznějších změn. Názory a myšlenky v tomto článku již nemusí vyjadřovat současné stanovisko autora nebo autorů. Článek byl napsán 26. října 2015.

Zaujala mě jedna certifikační otázka (MCSD / 70-487), která docela dobře pracuje s různými aspekty použití Entity Frameworku. Otázka s rozepsaným řešením bez cenzury.

Otázka

You are developing an ASP.NET MVC application. The application is an order processing system that uses the ADO.NET Entity Framework against a SQL Server database. It has a controller that loads a page that displays all orders along with customer information. Lazy loading has been disabled. The Order class is shown below.

public partial class Order
{
	public string CustomerId { get; set; }
	...
	public virtual Customer Customer { get; set; } 
}

You need to return the orders and customer information in a single round trip to the database. Which code segment should you use?

A

public ActionResult Index()
{
	IQueryable<Order> orders = db.Orders;
	orders = orders.Include("Customer");
	return View (orders.ToList());
}

B

public ActionResult Index()
{
	IQueryable<Order> orders = db.Orders.Include("Order.Customer")
	return View (orders.ToList());
}

C

public ActionResult Index()
{
	IQueryable<Order> orders = db.Orders;
	orders.Select(o => o.Customer).Load();
	return View (orders.ToList());
}

D

public ActionResult Index()
{
	IQueryable<Order> orders = db.Orders;
	return View (orders.ToList());
}

Na této otázce se mi líbí právě to, že každá možnost je na první pohled správná. Kód jde ve všech případech zkompilovat, nicméně výsledek se liší tím, jaká data se přenášejí z databáze.

Řešení

Důležité je dobře si přečíst zadání otázky. Jsou v něm požadavky a předpoklady, ze kterých správná odpověď jasně plyne. Důležité je hlavně následující:

  • Lazy loading has been disabled.
  • You need to return the orders and customer information in a single round trip to the database.

Protože je vypnutý Lazy Loading, můžeme rovnou vyloučit možnost D. Po odeslání dotazu se načtou pouze samotné objednávky bez zákazníka. Kdybychom chtěli později donačíst zákazník(a/y), neobešli bychom se bez dodatečných dotazů proti databázi.

Varianta C se jeví jako dobré řešení, protože třída Order má definovaného Customer jako virtual a tudíž můžeme skutečně použít explicitní loading. V hromadě ukázek na internetu je tato odpověď označená jako správná. Problém je, že v zadání je jasně řečeno: return data in a single round trip to the database. V případé této konstrukce se ale do databáze odesílá více dotazů v závilosti na použití Lazy Loadingu.

Zbývají možnosti A / B, které obě využívají Include() pro dotažení zákazníka. Obě varianty jsou syntakticky v pořádku ale varianta B odkazuje na "Order.Customer", což je chybné. Protože už nad objektem Order pracujeme, chceme použít jen Include("Customer").

Tím se dostáváme ke správné odpovědi A. Tady může na první pohled zmást konstrukce

IQueryable<Order> orders = db.Orders;

protože Db.Orders je typu DbSet<Order>. Přiřazení je ale v pořádku, viz.:

public class DbSet<TEntity> : DbQuery<TEntity>, IDbSet<TEntity>, 
    IQueryable<TEntity>, IEnumerable<TEntity>, IQueryable, IEnumerable
where TEntity : class
...

Odpálením dotazu dojde k načtení objednávek včetně zákazníků, čímž jsou splněny požadavky v otázce.

Při práci s EF lze jedné a té samé věci docílit mnoha různými způsoby. Sestavovat dotazy občas vyžaduje více zamyšlení nad tím, jaká data potřebuji, kdy je potřebuji a co s nimi chci dělat.

Školení ASP.NET Core a Entity Framework Core

Budoucnost platformy .NET bude patřit technologiím ASP.NET Core a EF Core. Přijďte se naučit tyto moderní technologie používat na mém praktickém školení.

6.11.2017 - 8.11.2017 ASP.NET Core MVC
20.11.2017 - 21.11.2017 Entity Framework Core