From 12051757e82c6cb7f37037f130e8ac8c2e51ddbe Mon Sep 17 00:00:00 2001 From: Kristoffer Blucher Date: Mon, 27 Jan 2025 10:34:12 +0100 Subject: [PATCH 1/3] Skeleton done --- exercise.pizzashopapi/Data/DataContext.cs | 1 + exercise.pizzashopapi/Data/Seeder.cs | 2 + .../EndPoints/PizzaShopApi.cs | 112 +++++++++++++++++- exercise.pizzashopapi/Models/Customer.cs | 3 + exercise.pizzashopapi/Models/Order.cs | 9 +- exercise.pizzashopapi/Models/Pizza.cs | 9 +- exercise.pizzashopapi/README.md | 31 +++++ .../Repository/IRepository.cs | 14 ++- .../Repository/Repository.cs | 53 ++++++++- 9 files changed, 225 insertions(+), 9 deletions(-) create mode 100644 exercise.pizzashopapi/README.md diff --git a/exercise.pizzashopapi/Data/DataContext.cs b/exercise.pizzashopapi/Data/DataContext.cs index 129199e..4fce5cb 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -1,6 +1,7 @@ using exercise.pizzashopapi.Models; using Microsoft.EntityFrameworkCore; + namespace exercise.pizzashopapi.Data { public class DataContext : DbContext diff --git a/exercise.pizzashopapi/Data/Seeder.cs b/exercise.pizzashopapi/Data/Seeder.cs index f87fbef..27d071a 100644 --- a/exercise.pizzashopapi/Data/Seeder.cs +++ b/exercise.pizzashopapi/Data/Seeder.cs @@ -12,12 +12,14 @@ public async static void SeedPizzaShopApi(this WebApplication app) { db.Add(new Customer() { Name="Nigel" }); db.Add(new Customer() { Name = "Dave" }); + db.Add(new Customer() { Name = "Kristoffer" }); await db.SaveChangesAsync(); } if(!db.Pizzas.Any()) { db.Add(new Pizza() { Name = "Cheese & Pineapple" }); db.Add(new Pizza() { Name = "Vegan Cheese Tastic" }); + db.Add(new Pizza() { Name = "Nduja" }); await db.SaveChangesAsync(); } diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index f8be2b0..1d4bf0d 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -1,4 +1,5 @@ -using exercise.pizzashopapi.Repository; +using System.Security.Cryptography.X509Certificates; +using exercise.pizzashopapi.Repository; using Microsoft.AspNetCore.Mvc; namespace exercise.pizzashopapi.EndPoints @@ -7,9 +8,114 @@ public static class PizzaShopApi { public static void ConfigurePizzaShopApi(this WebApplication app) { - + + var PizzaShop = app.MapGroup("PizzaShop"); + + PizzaShop.MapGet("/orders", GetOrders); + PizzaShop.MapGet("/order/{id}", GetOrderById); + + + PizzaShop.MapGet("/pizzas", GetPizzas); + PizzaShop.MapGet("/pizza/{id}", GetPizzaById); + + PizzaShop.MapGet("/customers", GetCustomers); + PizzaShop.MapGet("/customer/{id}", GetCustomerById); + + + } + + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public static async Task GetOrders(IRepository repo) + { + var orders = await repo.GetOrders(); + + if (orders == null) + + { + return TypedResults.NotFound("Could not find any orders"); + + } + return TypedResults.Ok(orders); + + + } + + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetOrderById(IRepository repo) + { + throw new NotImplementedException(); + + + } + + + + + + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public static async Task GetPizzas(IRepository repo) + { + var pizzas = await repo.GetPizzas(); + + if (pizzas == null) + + { + return TypedResults.NotFound("Could not find any pizzas"); + + } + + return TypedResults.Ok(pizzas); + + + } + + + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetPizzaById(IRepository repo) + { + throw new NotImplementedException(); + + + } + + + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType (StatusCodes.Status404NotFound)] + public static async Task GetCustomers(IRepository repo) + { + var customers = await repo.GetCustomers(); + + if (customers == null) + { + return TypedResults.NotFound("Could not find any customers"); + + } + + return TypedResults.Ok(customers); + + } - + + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetCustomerById(IRepository repo) + { + throw new NotImplementedException(); + + + } + + + + + + + + + + + } } diff --git a/exercise.pizzashopapi/Models/Customer.cs b/exercise.pizzashopapi/Models/Customer.cs index 2ca83bd..23015d6 100644 --- a/exercise.pizzashopapi/Models/Customer.cs +++ b/exercise.pizzashopapi/Models/Customer.cs @@ -4,7 +4,10 @@ namespace exercise.pizzashopapi.Models { public class Customer { + [Column("id")] public int Id { get; set; } + + [Column("customer_name")] public string Name { get; set; } } } diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index fbe6113..ac6ec22 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -4,7 +4,14 @@ namespace exercise.pizzashopapi.Models { public class Order { - + [Column("id")] + public int OrderId { get; set; } + + [ForeignKey("customer_id")] + public int CustomerId { get; set; } + + [ForeignKey("pizza_id")] + public int PizzaId { get; set; } } } diff --git a/exercise.pizzashopapi/Models/Pizza.cs b/exercise.pizzashopapi/Models/Pizza.cs index 5c085ec..e3d27c2 100644 --- a/exercise.pizzashopapi/Models/Pizza.cs +++ b/exercise.pizzashopapi/Models/Pizza.cs @@ -2,11 +2,16 @@ namespace exercise.pizzashopapi.Models { - + [Table("Pizza")] public class Pizza - { + { + [Column("id")] public int Id { get; set; } + + [Column("pizza_name")] public string Name { get; set; } + + [Column("price")] public decimal Price { get; set; } } } \ No newline at end of file diff --git a/exercise.pizzashopapi/README.md b/exercise.pizzashopapi/README.md new file mode 100644 index 0000000..714679a --- /dev/null +++ b/exercise.pizzashopapi/README.md @@ -0,0 +1,31 @@ +# C# Migrations Exercise + +## Pizza Shop Api + +Pizza Shop needs a very simple ordering system with just just 3 tables, Customer, Pizza and Order. + +## Setup +- Create, then add your credentials to the appsettings.json file and connect to your [neon](https://neon.tech) database. + +## Core + +- Write all endpoints in the PizzaShopApi.cs +- Use your initiative to create relevant endpoints such as GetOrders, GetOrdersByCustomerId, GetPizzas etc.. +- Use Dependency Injection to instance the DbContext Repository +- Inject the IRepository into the EndPoints in the PizzaShopApi +- An order consists of 1 customer ordering 1 pizza. +- Seed some data for the orders. Dave likes a Cheese & Pineapple pizza and Nigel likes Vegan ones. +- Include yourself as a customer and your favourite Pizza. + + +## Extension (choose at least two) + +- Add extra toppings to Pizzas and allow customers to add toppings to their order. Add a new table for Toppings and a new table for OrderToppings. Add any endpoints you think necessary to add toppings. +- Assume that Pizzas take 3 minutes to prepare and 12 minutes to cook in the oven. Modify your code so your customers see at what stage their order is and add an endpoint so the delivery drivers app can set the order as Delivered +- The Pizza Shop can only cook 4 pizzas at a time and the delivery driver is allocated 10 minutes to deliver one pizza at a time. Add an estimated delivery time to the Order! +- Add a new table for DeliveryDrivers and add an endpoint to assign a driver to an order. Add a new endpoint to get all orders for a driver. +- Add the ability for the Pizza shop to sell other products on the Menu. e.g. Burgers, Fries, Drinks. Update any existing code and add any endpoints you think necessary to add products these to an order. + + + +``` diff --git a/exercise.pizzashopapi/Repository/IRepository.cs b/exercise.pizzashopapi/Repository/IRepository.cs index b114ea8..52d56ec 100644 --- a/exercise.pizzashopapi/Repository/IRepository.cs +++ b/exercise.pizzashopapi/Repository/IRepository.cs @@ -4,7 +4,19 @@ namespace exercise.pizzashopapi.Repository { public interface IRepository { - Task> GetOrdersByCustomer(int id); + Task> GetOrdersByCustomerId(int id); + Task> GetCustomers(); + Task GetCustomerById(int id); + + + Task> GetOrders(); + + Task GetOrderById(int id); + + + Task> GetPizzas(); + Task GetPizzaById(int id); + } diff --git a/exercise.pizzashopapi/Repository/Repository.cs b/exercise.pizzashopapi/Repository/Repository.cs index e109fce..70293a9 100644 --- a/exercise.pizzashopapi/Repository/Repository.cs +++ b/exercise.pizzashopapi/Repository/Repository.cs @@ -6,9 +6,58 @@ namespace exercise.pizzashopapi.Repository public class Repository : IRepository { private DataContext _db; - public Task> GetOrdersByCustomer(int id) + public async Task> GetOrdersByCustomerId(int id) { throw new NotImplementedException(); } - } + + public async Task GetOrderById(int id) + { + + throw new NotImplementedException(); + + + } + + public async Task> GetOrders() + { + + throw new NotImplementedException(); + + } + + + public async Task> GetPizzas() + { + throw new NotImplementedException(); + + } + + public async Task GetPizzaById(int id) + { + + throw new NotImplementedException(); + + } + + + public async Task> GetCustomers() + { + throw new NotImplementedException(); + + + } + + + public async Task GetCustomerById(int id) + { + + throw new NotImplementedException(); + + } + + } + + + } From de4e0ebbd309c28bbfa7d8ea8788838d21ff932f Mon Sep 17 00:00:00 2001 From: Kristoffer Blucher Date: Mon, 27 Jan 2025 10:44:53 +0100 Subject: [PATCH 2/3] Endpoints core done --- .../EndPoints/PizzaShopApi.cs | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index 1d4bf0d..af44102 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -1,4 +1,5 @@ using System.Security.Cryptography.X509Certificates; +using exercise.pizzashopapi.Models; using exercise.pizzashopapi.Repository; using Microsoft.AspNetCore.Mvc; @@ -42,16 +43,20 @@ public static async Task GetOrders(IRepository repo) } [ProducesResponseType(StatusCodes.Status200OK)] - public static async Task GetOrderById(IRepository repo) + public static async Task GetOrderById(IRepository repo, int id) { - throw new NotImplementedException(); + var order = await repo.GetOrderById(id); + if (order == null) - } - + { + return TypedResults.NotFound($"Order with the id:{id} not found"); + } + return TypedResults.Ok(order); + } [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -68,18 +73,24 @@ public static async Task GetPizzas(IRepository repo) return TypedResults.Ok(pizzas); - } - [ProducesResponseType(StatusCodes.Status200OK)] - public static async Task GetPizzaById(IRepository repo) + [ProducesResponseType(StatusCodes.Status404NotFound)] + public static async Task GetPizzaById(IRepository repo, int id) + { - throw new NotImplementedException(); + var pizza = await repo.GetPizzaById(id); + if (pizza == null) - } + { + return TypedResults.NotFound($"Pizza with the id:{id} not found"); + } + return TypedResults.Ok(pizza); + + } [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType (StatusCodes.Status404NotFound)] @@ -94,16 +105,22 @@ public static async Task GetCustomers(IRepository repo) } return TypedResults.Ok(customers); - - } - [ProducesResponseType(StatusCodes.Status200OK)] - public static async Task GetCustomerById(IRepository repo) + [ProducesResponseType(StatusCodes.Status404NotFound)] + public static async Task GetCustomerById(IRepository repo, int id) { - throw new NotImplementedException(); + var customer = await repo.GetCustomerById(id); + + if (customer == null) + + { + return TypedResults.NotFound($"Customer with the id:{id} not found"); + + } + return TypedResults.Ok(customer); } From a74f5d2232f12fb5838fb9943bbd50aff129e1c7 Mon Sep 17 00:00:00 2001 From: Kristoffer Blucher Date: Mon, 27 Jan 2025 22:54:37 +0100 Subject: [PATCH 3/3] Core Done --- exercise.pizzashopapi/DTOS/CustomerDTO.cs | 14 +++ exercise.pizzashopapi/DTOS/OrderDTO.cs | 12 ++ exercise.pizzashopapi/DTOS/PizzaDTO.cs | 11 ++ exercise.pizzashopapi/Data/DataContext.cs | 16 ++- exercise.pizzashopapi/Data/Seeder.cs | 21 ++-- .../EndPoints/PizzaShopApi.cs | 59 ++++++++- .../20250127210936_Second.Designer.cs | 119 ++++++++++++++++++ .../Migrations/20250127210936_Second.cs | 91 ++++++++++++++ .../Migrations/DataContextModelSnapshot.cs | 116 +++++++++++++++++ exercise.pizzashopapi/Models/Customer.cs | 2 + exercise.pizzashopapi/Models/Order.cs | 7 +- exercise.pizzashopapi/Models/Pizza.cs | 3 +- exercise.pizzashopapi/Program.cs | 2 + .../Repository/IRepository.cs | 4 +- .../Repository/Repository.cs | 49 +++++--- .../exercise.pizzashopapi.csproj | 16 +-- 16 files changed, 500 insertions(+), 42 deletions(-) create mode 100644 exercise.pizzashopapi/DTOS/CustomerDTO.cs create mode 100644 exercise.pizzashopapi/DTOS/OrderDTO.cs create mode 100644 exercise.pizzashopapi/DTOS/PizzaDTO.cs create mode 100644 exercise.pizzashopapi/Migrations/20250127210936_Second.Designer.cs create mode 100644 exercise.pizzashopapi/Migrations/20250127210936_Second.cs create mode 100644 exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs diff --git a/exercise.pizzashopapi/DTOS/CustomerDTO.cs b/exercise.pizzashopapi/DTOS/CustomerDTO.cs new file mode 100644 index 0000000..6e30366 --- /dev/null +++ b/exercise.pizzashopapi/DTOS/CustomerDTO.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Xml.Linq; + +namespace exercise.pizzashopapi.DTOS +{ + public class CustomerDTO + { + + public int CustomerId { get; set; } + public string Name { get; set; } + public List Orders { get; set;} = new List(); + } +} + diff --git a/exercise.pizzashopapi/DTOS/OrderDTO.cs b/exercise.pizzashopapi/DTOS/OrderDTO.cs new file mode 100644 index 0000000..3aaddfb --- /dev/null +++ b/exercise.pizzashopapi/DTOS/OrderDTO.cs @@ -0,0 +1,12 @@ +using exercise.pizzashopapi.Models; + +namespace exercise.pizzashopapi.DTOS +{ + public class OrderDTO + { + public string CustomerName { get; set; } + public string PizzaName { get; set; } + public decimal Price { get; set; } + + } +} diff --git a/exercise.pizzashopapi/DTOS/PizzaDTO.cs b/exercise.pizzashopapi/DTOS/PizzaDTO.cs new file mode 100644 index 0000000..2f97e1b --- /dev/null +++ b/exercise.pizzashopapi/DTOS/PizzaDTO.cs @@ -0,0 +1,11 @@ +namespace exercise.pizzashopapi.DTOS +{ + public class PizzaDTO + { + public int PizzaId { get; set; } + public string PizzaName { get; set; } + public decimal Price { get; set; } + + + } +} diff --git a/exercise.pizzashopapi/Data/DataContext.cs b/exercise.pizzashopapi/Data/DataContext.cs index 4fce5cb..14e64b9 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -1,4 +1,5 @@ -using exercise.pizzashopapi.Models; +using System.Diagnostics; +using exercise.pizzashopapi.Models; using Microsoft.EntityFrameworkCore; @@ -10,18 +11,29 @@ public class DataContext : DbContext public DataContext() { var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); - connectionString = configuration.GetValue("ConnectionStrings:DefaultConnectionString"); + connectionString = configuration.GetValue("ConnectionStrings:DefaultConnectionString")!; + this.Database.EnsureCreated(); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseNpgsql(connectionString); + optionsBuilder.LogTo(message => Debug.WriteLine(message)); //set primary of order? //seed data? } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasKey(o => o.Id); + + } + + public DbSet Pizzas { get; set; } public DbSet Customers { get; set; } public DbSet Orders { get; set; } diff --git a/exercise.pizzashopapi/Data/Seeder.cs b/exercise.pizzashopapi/Data/Seeder.cs index 27d071a..a0e9bd8 100644 --- a/exercise.pizzashopapi/Data/Seeder.cs +++ b/exercise.pizzashopapi/Data/Seeder.cs @@ -10,23 +10,28 @@ public async static void SeedPizzaShopApi(this WebApplication app) { if(!db.Customers.Any()) { - db.Add(new Customer() { Name="Nigel" }); - db.Add(new Customer() { Name = "Dave" }); - db.Add(new Customer() { Name = "Kristoffer" }); + db.Add(new Customer() {Id = 1, Name="Nigel" }); + db.Add(new Customer() {Id = 2, Name = "Dave" }); + db.Add(new Customer() {Id = 3, Name = "Kristoffer" }); await db.SaveChangesAsync(); } if(!db.Pizzas.Any()) { - db.Add(new Pizza() { Name = "Cheese & Pineapple" }); - db.Add(new Pizza() { Name = "Vegan Cheese Tastic" }); - db.Add(new Pizza() { Name = "Nduja" }); + db.Add(new Pizza() {Id = 1, Name = "Cheese & Pineapple" , Price = 190m }); + db.Add(new Pizza() {Id = 2, Name = "Vegan Cheese Tastic", Price = 200m }); + db.Add(new Pizza() {Id = 3, Name = "Nduja", Price = 210m }); await db.SaveChangesAsync(); } - //order data - if(1==1) + + if(!db.Orders.Any()) { + db.Add(new Order() { Id = 1, CustomerId = 1, PizzaId = 1 }); + db.Add(new Order() { Id = 2, CustomerId = 2, PizzaId = 2 }); + db.Add(new Order() { Id = 3, CustomerId = 3, PizzaId = 3 }); + + await db.SaveChangesAsync(); } diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index af44102..32f9cf0 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -1,4 +1,5 @@ using System.Security.Cryptography.X509Certificates; +using exercise.pizzashopapi.DTOS; using exercise.pizzashopapi.Models; using exercise.pizzashopapi.Repository; using Microsoft.AspNetCore.Mvc; @@ -37,7 +38,16 @@ public static async Task GetOrders(IRepository repo) return TypedResults.NotFound("Could not find any orders"); } - return TypedResults.Ok(orders); + + var orderDto = orders.Select( o => new OrderDTO + { + + CustomerName = o.Customer.Name, + PizzaName = o.Pizza.Name, + Price = o.Pizza.Price, + }).ToList(); + + return TypedResults.Ok(orderDto); } @@ -54,7 +64,16 @@ public static async Task GetOrderById(IRepository repo, int id) } - return TypedResults.Ok(order); + var orderDto = new OrderDTO + + { + CustomerName= order.Customer.Name, + PizzaName= order.Pizza.Name, + Price = order.Pizza.Price, + + }; + + return TypedResults.Ok(orderDto); } @@ -71,7 +90,14 @@ public static async Task GetPizzas(IRepository repo) } - return TypedResults.Ok(pizzas); + var pizzaDto = pizzas.Select(p => new PizzaDTO + { + PizzaId = p.Id, + PizzaName = p.Name, + Price = p.Price, + }).ToList(); + + return TypedResults.Ok(pizzaDto); } @@ -88,7 +114,15 @@ public static async Task GetPizzaById(IRepository repo, int id) return TypedResults.NotFound($"Pizza with the id:{id} not found"); } - return TypedResults.Ok(pizza); + var pizzaDto = new PizzaDTO + { + PizzaId = pizza.Id, + PizzaName = pizza.Name, + Price = pizza.Price, + + }; + + return TypedResults.Ok(pizzaDto); } @@ -104,7 +138,13 @@ public static async Task GetCustomers(IRepository repo) } - return TypedResults.Ok(customers); + var customerDto = customers.Select(c => new CustomerDTO + { + CustomerId = c.Id, + Name = c.Name + }).ToList(); + + return TypedResults.Ok(customerDto); } [ProducesResponseType(StatusCodes.Status200OK)] @@ -120,7 +160,14 @@ public static async Task GetCustomerById(IRepository repo, int id) } - return TypedResults.Ok(customer); + var customerDto = new CustomerDTO + + { + CustomerId = customer.Id, + Name = customer.Name + }; + + return TypedResults.Ok(customerDto); } diff --git a/exercise.pizzashopapi/Migrations/20250127210936_Second.Designer.cs b/exercise.pizzashopapi/Migrations/20250127210936_Second.Designer.cs new file mode 100644 index 0000000..b977f97 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127210936_Second.Designer.cs @@ -0,0 +1,119 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using exercise.pizzashopapi.Data; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20250127210936_Second")] + partial class Second + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("customer_name"); + + b.HasKey("Id"); + + b.ToTable("customer"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PizzaId"); + + b.ToTable("order"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("pizza_name"); + + b.Property("Price") + .HasColumnType("numeric") + .HasColumnName("price"); + + b.HasKey("Id"); + + b.ToTable("pizza"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.HasOne("exercise.pizzashopapi.Models.Customer", "Customer") + .WithMany("Orders") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Pizza", "Pizza") + .WithMany() + .HasForeignKey("PizzaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + + b.Navigation("Pizza"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Navigation("Orders"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250127210936_Second.cs b/exercise.pizzashopapi/Migrations/20250127210936_Second.cs new file mode 100644 index 0000000..01cbba8 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127210936_Second.cs @@ -0,0 +1,91 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class Second : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "customer", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + customer_name = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_customer", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "pizza", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + pizza_name = table.Column(type: "text", nullable: false), + price = table.Column(type: "numeric", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_pizza", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "order", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + CustomerId = table.Column(type: "integer", nullable: false), + PizzaId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_order", x => x.id); + table.ForeignKey( + name: "FK_order_customer_CustomerId", + column: x => x.CustomerId, + principalTable: "customer", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_order_pizza_PizzaId", + column: x => x.PizzaId, + principalTable: "pizza", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_order_CustomerId", + table: "order", + column: "CustomerId"); + + migrationBuilder.CreateIndex( + name: "IX_order_PizzaId", + table: "order", + column: "PizzaId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "order"); + + migrationBuilder.DropTable( + name: "customer"); + + migrationBuilder.DropTable( + name: "pizza"); + } + } +} diff --git a/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs b/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs new file mode 100644 index 0000000..36b1917 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs @@ -0,0 +1,116 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using exercise.pizzashopapi.Data; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + [DbContext(typeof(DataContext))] + partial class DataContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("customer_name"); + + b.HasKey("Id"); + + b.ToTable("customer"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PizzaId"); + + b.ToTable("order"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("pizza_name"); + + b.Property("Price") + .HasColumnType("numeric") + .HasColumnName("price"); + + b.HasKey("Id"); + + b.ToTable("pizza"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.HasOne("exercise.pizzashopapi.Models.Customer", "Customer") + .WithMany("Orders") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Pizza", "Pizza") + .WithMany() + .HasForeignKey("PizzaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + + b.Navigation("Pizza"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Navigation("Orders"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Models/Customer.cs b/exercise.pizzashopapi/Models/Customer.cs index 23015d6..41f0506 100644 --- a/exercise.pizzashopapi/Models/Customer.cs +++ b/exercise.pizzashopapi/Models/Customer.cs @@ -2,6 +2,7 @@ namespace exercise.pizzashopapi.Models { + [Table("customer")] public class Customer { [Column("id")] @@ -9,5 +10,6 @@ public class Customer [Column("customer_name")] public string Name { get; set; } + public ICollection Orders { get; set; } = new List (); } } diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index ac6ec22..a27e53f 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -2,16 +2,19 @@ namespace exercise.pizzashopapi.Models { + [Table("order")] public class Order { [Column("id")] - public int OrderId { get; set; } + public int Id { get; set; } [ForeignKey("customer_id")] public int CustomerId { get; set; } [ForeignKey("pizza_id")] public int PizzaId { get; set; } - + + public Customer Customer { get; set; } + public Pizza Pizza { get; set; } } } diff --git a/exercise.pizzashopapi/Models/Pizza.cs b/exercise.pizzashopapi/Models/Pizza.cs index e3d27c2..755254e 100644 --- a/exercise.pizzashopapi/Models/Pizza.cs +++ b/exercise.pizzashopapi/Models/Pizza.cs @@ -1,8 +1,9 @@ using System.ComponentModel.DataAnnotations.Schema; +using exercise.pizzashopapi.Repository; namespace exercise.pizzashopapi.Models { - [Table("Pizza")] + [Table("pizza")] public class Pizza { [Column("id")] diff --git a/exercise.pizzashopapi/Program.cs b/exercise.pizzashopapi/Program.cs index c04a440..6dbb372 100644 --- a/exercise.pizzashopapi/Program.cs +++ b/exercise.pizzashopapi/Program.cs @@ -22,6 +22,8 @@ app.UseSwaggerUI(); } + + app.UseHttpsRedirection(); app.UseAuthorization(); diff --git a/exercise.pizzashopapi/Repository/IRepository.cs b/exercise.pizzashopapi/Repository/IRepository.cs index 52d56ec..eb53d5f 100644 --- a/exercise.pizzashopapi/Repository/IRepository.cs +++ b/exercise.pizzashopapi/Repository/IRepository.cs @@ -5,11 +5,11 @@ namespace exercise.pizzashopapi.Repository public interface IRepository { Task> GetOrdersByCustomerId(int id); - Task> GetCustomers(); + Task> GetCustomers(); Task GetCustomerById(int id); - Task> GetOrders(); + Task> GetOrders(); Task GetOrderById(int id); diff --git a/exercise.pizzashopapi/Repository/Repository.cs b/exercise.pizzashopapi/Repository/Repository.cs index 70293a9..452ecef 100644 --- a/exercise.pizzashopapi/Repository/Repository.cs +++ b/exercise.pizzashopapi/Repository/Repository.cs @@ -1,49 +1,68 @@ using exercise.pizzashopapi.Data; using exercise.pizzashopapi.Models; +using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Repository { public class Repository : IRepository { private DataContext _db; - public async Task> GetOrdersByCustomerId(int id) + + public Repository(DataContext db) + + { + _db = db; + + } + + public async Task> GetOrdersByCustomerId(int customerId) { - throw new NotImplementedException(); + return await _db.Orders.Include(o => o.Pizza).Where(o => o.CustomerId == customerId).ToListAsync(); } public async Task GetOrderById(int id) - { - - throw new NotImplementedException(); - - + { + var order = await _db.Orders.Include(o => o.Pizza).Include(c => c.Customer).FirstOrDefaultAsync(c => c.Id == id); + + return order; + } - public async Task> GetOrders() + public async Task> GetOrders() { - throw new NotImplementedException(); + + var orders = await _db.Orders.Include( o => o.Customer).Include(o => o.Pizza).ToListAsync(); + + return orders; } public async Task> GetPizzas() { - throw new NotImplementedException(); + var pizzas = await _db.Pizzas.ToListAsync(); + + return pizzas; } public async Task GetPizzaById(int id) { + + var pizza = await _db.Pizzas.FirstOrDefaultAsync(p => p.Id == id); + + return pizza; - throw new NotImplementedException(); } - public async Task> GetCustomers() + public async Task> GetCustomers() { - throw new NotImplementedException(); + var customers = await _db.Customers.ToListAsync(); + + return customers; } @@ -52,7 +71,9 @@ public async Task> GetCustomers() public async Task GetCustomerById(int id) { - throw new NotImplementedException(); + var customer = await _db.Customers.Include(c => c.Orders).ThenInclude(c => c.Pizza).FirstOrDefaultAsync(c => c.Id == id); + + return customer; } diff --git a/exercise.pizzashopapi/exercise.pizzashopapi.csproj b/exercise.pizzashopapi/exercise.pizzashopapi.csproj index 624203b..88364b2 100644 --- a/exercise.pizzashopapi/exercise.pizzashopapi.csproj +++ b/exercise.pizzashopapi/exercise.pizzashopapi.csproj @@ -1,4 +1,4 @@ - + net9.0 @@ -11,18 +11,20 @@ - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + +