Opgave: EF Code First - Relations between Classes Using LINQ/DAO

Kilde: https://www.c-sharpcorner.com/article/navigation-property-with-code-first-navigation-property-in-ef/
I denne opgave tager vi udgangspunkt i eksemplet ItemsRazor ItemRazorV10.zip





Opgaven går ud på at udvide applikationen så en User der er logget ind kan bestille Items fra tabellen. Dvs der skal udvides med en klasse Order.
Klassen Order skal have referencer til Item og User så det er muligt at se relationen mellem User og Item via Order


Step 1 (Models - Order)
Opret en ny klasse Order, klassen skal have følgende properties:

  1. OrderId (unikt nummer, der skal genereres af databasen)
  2. Date (der angiver bestillings tidspunktet, Datetime.Now)
  3. UserId (Id på den user der afgiver bestilling, not null)
  4. User (den User der har foretaget bestillingen, navigation property)
  5. ItemId (Id på det Item der bestilles, not null)
  6. Item (det Computer Item der bestilles, navigation property)
  7. Count (der angiver antal der bestilles, > 0)

Husk: passende konstruktør(er) og passende DataAnnotations så databasen kan migreres og opdateres fx. [DatabaseGenerated(DatabaseGeneratedOption.Identity)]



Step 2 ( Models - User)

Opdater User med følgende properties:


Step 3 (ItemDbContext.cs)

Opdater ItemDbContext med et DbSet<Order>



Step 4 ( PMC)
Migrerer og opdater databasen med PMC

 

Applikationen skal nu udvides så det bliver muligt at bestille Items fra tabellen (fx ved klik på en ny knap under actions i tabellen) ala:.

 



Step 5 (OrderService.cs)

Først skal der oprettes en Service så der kan oprettes og gemmes nye Ordre.


Step 6 (OrderItem.cshtml.cs)
Der skal nu oprettes en Razor Page til oprettelse af nye ordre.

OrderItemModel skal benytte

Samt have følgende properties:

OnGet(int id) og OnPost(int id) kan se ud som følger:

public void OnGet(int id)
{
Item = itemService.GetItem(id);
User = userService.GetUserByUserName(HttpContext.User.Identity.Name);
}

public IActionResult OnPost(int id)
{
if (!ModelState.IsValid)
{
return Page();
}
Item = itemService.GetItem(id);
User = userService.GetUserByUserName(HttpContext.User.Identity.Name);
Order.UserId = User.UserId;
Order.ItemId = Item.ItemId;
Order.Date=DateTime.Now;
Order.Count = Count;
orderService.AddOrder(Order);
return RedirectToPage("../Item/GetAllItems");
}

 

Step 7 (OrderItem.cshtml)
Implementer html-siden med et form-tag, så der kan indtastes det antal items der skal bestilles.

 

Step 8 (GetAllItems.cshtml)
Udvid "Oversigtssiden" med en bestillings knap ala:

<li class="list-inline-item">
<a class="btn btn-primary btn-sm " type="button" .... asp-page="../Order/OrderItem" asp-route-id="@item.ItemId"><i class="fa fa-shopping-cart"></i></a>
</li>

Tilret tabellen fx med diverse <col style="width: XX%"> så knapperne står pænt.

 

Step 9 (Afprøv)
Afprøv at den nye funktionalitet virker.
Hint: Benyt SQL Server Object Explorer til at verificere at ordre bliver tilføjet tabellen.

 

Applikationen skal nu udvides så man kan se current users ordre (ala "mine ordre" for den bruger der er logget ind).
Den metode der benyttes her er et alternativ til et egentligt Database View. Det minder om SQL-Views, men her benyttes LINQ på DBSet i DBContext i stedet for at lave SQL-udtræk fra DB-tabellerne.
Der vil blive benyttet DAO (Data Access Object), hvilket er hjælpe-objekter der "matcher" de data der skal vises i "Viewet"

 

Step 10 (OrderDAO)
Opret en mappe DAO med en klasse OrderDAO. Klassen skal have følgende properties:

public int OrderId { get; set; }
public DateTime Date { get; set; }
public int ItemId { get; set; }
public string ItemName { get; set; }
public decimal Price { get; set; }
public int UserId { get; set; }
public string UserName { get; set; }
public int Count { get; set; }

Det er de data der ønskes vist i på siden MyOrders, der skal udvikles senere.

 

Step 11 (UserDbService.cs)
Der skal nu benyttes udvidet funktionalitet i forhold til DbGenericService<User>, derfor oprettes en ny Service klasse: UserDbService der extender DbGenericService med en ny metode: GetOrdersByUserIdAsync(int id). Denne metode skal returnere en List<OrderDAO> der indeholder de objekter der findes ved følgende LINQ-udtryk:

var orders = from order in context.Orders
join item in context.Items on order.ItemId equals item.ItemId
join user in context.Users on order.UserId equals user.UserId
where user.UserId == id
select new OrderDAO()
{
OrderId = order.OrderId,
Date = order.Date,
UserId = user.UserId,
UserName = user.UserName,
ItemId = item.ItemId,
ItemName = item.Name,
Price = item.Price,
Count = order.Count
};

Hint: Opret en lokal variabel: List<OrderDAO> orderList = new List<OrderDAO>(); og returner denne efter at objekterne i orders er tilføjet til listen.
LINQ-udtrykket og foreach pakkes ind i en using, hvor der oprettes en instans af ItemDbContext.

 

Step 12 (UserService.cs)
Refaktorer UserService så den benytter UserDbService i stedet for DbGenericService<User> (Husk iøvrigt at opdatere Startup.cs)

Tilføj en metode: GetUserOrders(User user) der benytter den nye service til at hente og returnere OrderDAO-objekterne.


Step 13 (MyOrders.cshtml.cs)
Opret en ny Razor Pages MyOrders til at vise current users ordre.

MyOrdersModel skal benytte UserService og have en IEnumerable eller List af OrderDAO objekter som initialiseres af OnGet( ) ved kald af GetUserOrders(...)

Hint:

User CurrentUser = UserService.GetUserByUserName(HttpContext.User.Identity.Name);
MyOrders = UserService.GetUserOrders(CurrentUser);

 

Step 14 (MyOrders.cshtml)
Implementer siden så alle oplysninger om current users ordre vises ala:


Husk: at tilføje link til siden i _Layout.cs

 

Step 15 (Afprøv)
Afprøv at den nye funktionalitet virker.

 

Step 16 (Ekstra)
Find selv på ekstra features/udvidelser til applikationen.

 


God fornøjelse!
Henrik Høltzer