From d8c29df0b5a36e2d750844966044901944ee1060 Mon Sep 17 00:00:00 2001 From: Sander Rasmussen Date: Mon, 27 Jan 2025 15:47:19 +0100 Subject: [PATCH 1/8] connected to db i think --- exercise.pizzashopapi/Data/DataContext.cs | 7 ++++--- exercise.pizzashopapi/Models/Order.cs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/exercise.pizzashopapi/Data/DataContext.cs b/exercise.pizzashopapi/Data/DataContext.cs index 129199e..a2fac38 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -6,11 +6,12 @@ namespace exercise.pizzashopapi.Data public class DataContext : DbContext { private string connectionString; - public DataContext() + public DataContext() { var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); - connectionString = configuration.GetValue("ConnectionStrings:DefaultConnectionString"); - + connectionString = configuration.GetValue("ConnectionStrings:DefaultConnectionString")!; + this.Database.SetConnectionString(connectionString); + this.Database.EnsureCreated(); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index fbe6113..375a5ec 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -5,6 +5,6 @@ namespace exercise.pizzashopapi.Models public class Order { - + public int Id { get; set; } } } From afa3ce9794e466a93c4de9bc258048d4458465e5 Mon Sep 17 00:00:00 2001 From: Sander Rasmussen Date: Mon, 27 Jan 2025 20:51:28 +0100 Subject: [PATCH 2/8] made basic skeleton --- exercise.pizzashopapi/DTO/CustomerDTO.cs | 13 ++++++++ exercise.pizzashopapi/DTO/OrderDTO.cs | 13 ++++++++ exercise.pizzashopapi/DTO/PizzaDTO.cs | 13 ++++++++ exercise.pizzashopapi/Data/DataContext.cs | 32 +++++++++++++++++++ .../EndPoints/PizzaShopApi.cs | 17 ++++++++-- exercise.pizzashopapi/Models/Customer.cs | 8 +++++ exercise.pizzashopapi/Models/Order.cs | 9 +++++- exercise.pizzashopapi/Models/Pizza.cs | 11 +++++-- .../Repository/IRepository.cs | 5 +-- .../Repository/Repository.cs | 11 +++++-- 10 files changed, 122 insertions(+), 10 deletions(-) create mode 100644 exercise.pizzashopapi/DTO/CustomerDTO.cs create mode 100644 exercise.pizzashopapi/DTO/OrderDTO.cs create mode 100644 exercise.pizzashopapi/DTO/PizzaDTO.cs diff --git a/exercise.pizzashopapi/DTO/CustomerDTO.cs b/exercise.pizzashopapi/DTO/CustomerDTO.cs new file mode 100644 index 0000000..50de6c1 --- /dev/null +++ b/exercise.pizzashopapi/DTO/CustomerDTO.cs @@ -0,0 +1,13 @@ +using exercise.pizzashopapi.Models; +using System.ComponentModel.DataAnnotations.Schema; + +namespace exercise.pizzashopapi.DTO +{ + public class CustomerDTO + { + public int Id { get; set; } + public string Name { get; set; } + public List Orders { get; set; } = new List(); + + } +} diff --git a/exercise.pizzashopapi/DTO/OrderDTO.cs b/exercise.pizzashopapi/DTO/OrderDTO.cs new file mode 100644 index 0000000..343763a --- /dev/null +++ b/exercise.pizzashopapi/DTO/OrderDTO.cs @@ -0,0 +1,13 @@ +using exercise.pizzashopapi.Models; +using System.ComponentModel.DataAnnotations.Schema; + +namespace exercise.pizzashopapi.DTO +{ + public class OrderDTO + { + + public int Id { get; set; } + public string customer { get; set; } + public List pizzas { get; set; } + } +} diff --git a/exercise.pizzashopapi/DTO/PizzaDTO.cs b/exercise.pizzashopapi/DTO/PizzaDTO.cs new file mode 100644 index 0000000..0eb0efc --- /dev/null +++ b/exercise.pizzashopapi/DTO/PizzaDTO.cs @@ -0,0 +1,13 @@ +using exercise.pizzashopapi.Models; +using System.ComponentModel.DataAnnotations.Schema; + +namespace exercise.pizzashopapi.DTO +{ + public class PizzaDTO + { + public int Id { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } + public List Orders { get; set; } = new List(); + } +} diff --git a/exercise.pizzashopapi/Data/DataContext.cs b/exercise.pizzashopapi/Data/DataContext.cs index a2fac38..37842c3 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -17,10 +17,42 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseNpgsql(connectionString); + //set primary of order? //seed data? + } + protected override async void OnModelCreating(ModelBuilder modelBuilder) + { + //defining primary keys + modelBuilder.Entity() + .HasKey(a => a.Id); + modelBuilder.Entity() + .HasKey(a => a.Id); + modelBuilder.Entity() + .HasKey(a => a.Id); + + //defining relations + modelBuilder.Entity() + .HasMany(a => a.Orders) + .WithOne(a => a.customer) + .HasForeignKey(a => a.Id); + + modelBuilder.Entity() + .HasMany(a => a.Orders) + .WithMany(a => a.pizzas); + + + modelBuilder.Entity() + .HasMany(a => a.pizzas) + .WithMany(a => a.Orders); + + + modelBuilder.Entity() + .HasOne(a => a.customer) + .WithMany(a => a.Orders); + } public DbSet Pizzas { get; set; } public DbSet Customers { get; set; } diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index f8be2b0..68f0932 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -1,4 +1,5 @@ -using exercise.pizzashopapi.Repository; +using exercise.pizzashopapi.DTO; +using exercise.pizzashopapi.Repository; using Microsoft.AspNetCore.Mvc; namespace exercise.pizzashopapi.EndPoints @@ -7,9 +8,19 @@ public static class PizzaShopApi { public static void ConfigurePizzaShopApi(this WebApplication app) { - + var pizzaGroup = app.MapGroup("pizzashop"); + + pizzaGroup.MapGet("/GetOrdersByCustomer", GetOrdersByCustomer); + + } + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetOrdersByCustomer(IRepository repo, int customerId) + { + var orders = repo.GetOrdersByCustomer(customerId); + //make it into DTO + List orderDTOs = new List(); - + } } } diff --git a/exercise.pizzashopapi/Models/Customer.cs b/exercise.pizzashopapi/Models/Customer.cs index 2ca83bd..9c8c4d8 100644 --- a/exercise.pizzashopapi/Models/Customer.cs +++ b/exercise.pizzashopapi/Models/Customer.cs @@ -1,10 +1,18 @@ using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Models { + [Table("Customer")] + [PrimaryKey("Id")] public class Customer { + [Column("Id")] public int Id { get; set; } + [Column("Name")] public string Name { get; set; } + [Column("Orders")] + public List Orders { get; set; } = new List(); + } } diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index 375a5ec..d4847f0 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -1,10 +1,17 @@ using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Models { + [Table("Order")] + [PrimaryKey("Id")] public class Order { - + [Column("Id")] public int Id { get; set; } + [Column("Customer")] + public Customer customer {get; set;} + [Column("Pizzas")] + public List pizzas {get; set;} } } diff --git a/exercise.pizzashopapi/Models/Pizza.cs b/exercise.pizzashopapi/Models/Pizza.cs index 5c085ec..293e51e 100644 --- a/exercise.pizzashopapi/Models/Pizza.cs +++ b/exercise.pizzashopapi/Models/Pizza.cs @@ -1,12 +1,19 @@ using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Models { - + [Table("Pizza")] + [PrimaryKey("Id")] public class Pizza - { + { + [Column("Id")] public int Id { get; set; } + [Column("Name")] public string Name { get; set; } + [Column("Price")] public decimal Price { get; set; } + [NotMapped] + public List Orders { get; set; } = new List(); } } \ No newline at end of file diff --git a/exercise.pizzashopapi/Repository/IRepository.cs b/exercise.pizzashopapi/Repository/IRepository.cs index b114ea8..74e3a69 100644 --- a/exercise.pizzashopapi/Repository/IRepository.cs +++ b/exercise.pizzashopapi/Repository/IRepository.cs @@ -4,8 +4,9 @@ namespace exercise.pizzashopapi.Repository { public interface IRepository { - Task> GetOrdersByCustomer(int id); - + public Task> GetOrdersByCustomer(int id); + + } } diff --git a/exercise.pizzashopapi/Repository/Repository.cs b/exercise.pizzashopapi/Repository/Repository.cs index e109fce..6ade84e 100644 --- a/exercise.pizzashopapi/Repository/Repository.cs +++ b/exercise.pizzashopapi/Repository/Repository.cs @@ -1,14 +1,21 @@ using exercise.pizzashopapi.Data; using exercise.pizzashopapi.Models; +using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Repository { public class Repository : IRepository { private DataContext _db; - public Task> GetOrdersByCustomer(int id) + public Repository(DataContext db) { - throw new NotImplementedException(); + _db = db; + } + public async Task> GetOrdersByCustomer(int id) + { + List orders = await _db.Orders.Include(a => a.customer).Include(b => b.pizzas).ToListAsync(); + var order = orders.FindAll(a => a.Id == id); + return order; } } } From bd9f9d4548bcbdb5ba2cbba4dbbc30b8e2888005 Mon Sep 17 00:00:00 2001 From: Sander Rasmussen Date: Mon, 27 Jan 2025 22:43:14 +0100 Subject: [PATCH 3/8] sleepy --- exercise.pizzashopapi/DTO/CustomerDTO.cs | 6 ++++++ exercise.pizzashopapi/DTO/OrderDTO.cs | 10 +++++++++- exercise.pizzashopapi/DTO/PizzaDTO.cs | 8 ++++++++ exercise.pizzashopapi/Data/DataContext.cs | 10 +++++++--- exercise.pizzashopapi/EndPoints/PizzaShopApi.cs | 6 ++++-- 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/exercise.pizzashopapi/DTO/CustomerDTO.cs b/exercise.pizzashopapi/DTO/CustomerDTO.cs index 50de6c1..15dace4 100644 --- a/exercise.pizzashopapi/DTO/CustomerDTO.cs +++ b/exercise.pizzashopapi/DTO/CustomerDTO.cs @@ -9,5 +9,11 @@ public class CustomerDTO public string Name { get; set; } public List Orders { get; set; } = new List(); + public CustomerDTO(Customer customer) + { + Id = customer.Id; + Name = customer.Name; + customer.Orders.ForEach(x => Orders.Add($"{x.pizzas}")); + } } } diff --git a/exercise.pizzashopapi/DTO/OrderDTO.cs b/exercise.pizzashopapi/DTO/OrderDTO.cs index 343763a..6b5b6ec 100644 --- a/exercise.pizzashopapi/DTO/OrderDTO.cs +++ b/exercise.pizzashopapi/DTO/OrderDTO.cs @@ -8,6 +8,14 @@ public class OrderDTO public int Id { get; set; } public string customer { get; set; } - public List pizzas { get; set; } + public List pizzas { get; set; } = new List(); + + public OrderDTO(Order order) + { + Id = order.Id; + customer= order.customer.Name; + order.pizzas.ForEach(x=> pizzas.Add($"{x.Name} {x.Price}")); + + } } } diff --git a/exercise.pizzashopapi/DTO/PizzaDTO.cs b/exercise.pizzashopapi/DTO/PizzaDTO.cs index 0eb0efc..9b21e97 100644 --- a/exercise.pizzashopapi/DTO/PizzaDTO.cs +++ b/exercise.pizzashopapi/DTO/PizzaDTO.cs @@ -9,5 +9,13 @@ public class PizzaDTO public string Name { get; set; } public decimal Price { get; set; } public List Orders { get; set; } = new List(); + public PizzaDTO(Pizza pizza) + { + Id = pizza.Id; + Name = pizza.Name; + Price = pizza.Price; + pizza.Orders.ForEach(x => Orders.Add($"{x.pizzas} {x.customer}")); + + } } } diff --git a/exercise.pizzashopapi/Data/DataContext.cs b/exercise.pizzashopapi/Data/DataContext.cs index 37842c3..9e96f96 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -6,7 +6,7 @@ namespace exercise.pizzashopapi.Data public class DataContext : DbContext { private string connectionString; - public DataContext() + public DataContext(DbContextOptions options) : base(options) { var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); connectionString = configuration.GetValue("ConnectionStrings:DefaultConnectionString")!; @@ -14,7 +14,7 @@ public DataContext() this.Database.EnsureCreated(); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { + { optionsBuilder.UseNpgsql(connectionString); @@ -52,8 +52,12 @@ protected override async void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity() .HasOne(a => a.customer) .WithMany(a => a.Orders); - + + //seeding + } + + public DbSet Pizzas { get; set; } public DbSet Customers { get; set; } public DbSet Orders { get; set; } diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index 68f0932..46e5059 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -1,4 +1,5 @@ using exercise.pizzashopapi.DTO; +using exercise.pizzashopapi.Models; using exercise.pizzashopapi.Repository; using Microsoft.AspNetCore.Mvc; @@ -17,10 +18,11 @@ public static void ConfigurePizzaShopApi(this WebApplication app) [ProducesResponseType(StatusCodes.Status200OK)] public static async Task GetOrdersByCustomer(IRepository repo, int customerId) { - var orders = repo.GetOrdersByCustomer(customerId); + var orders = await repo.GetOrdersByCustomer(customerId); //make it into DTO List orderDTOs = new List(); - + orders.ToList().ForEach(x => orderDTOs.Add(new OrderDTO(x))); + return TypedResults.Ok(orderDTOs); } } } From 117e0466abe93c9ed365a9187a703ecd56120639 Mon Sep 17 00:00:00 2001 From: Sander Rasmussen Date: Tue, 28 Jan 2025 10:10:17 +0100 Subject: [PATCH 4/8] Done with core --- exercise.pizzashopapi/DTO/CustomerDTO.cs | 2 +- exercise.pizzashopapi/DTO/OrderDTO.cs | 4 +- exercise.pizzashopapi/DTO/PizzaDTO.cs | 2 +- exercise.pizzashopapi/Data/DataContext.cs | 14 +- exercise.pizzashopapi/Data/Seeder.cs | 9 +- .../EndPoints/PizzaShopApi.cs | 36 +++++ .../20250128082304_InitialCreate.Designer.cs | 126 ++++++++++++++++++ .../20250128082304_InitialCreate.cs | 91 +++++++++++++ .../Migrations/DataContextModelSnapshot.cs | 123 +++++++++++++++++ exercise.pizzashopapi/Models/Order.cs | 8 +- .../Repository/IRepository.cs | 6 +- .../Repository/Repository.cs | 27 +++- 12 files changed, 431 insertions(+), 17 deletions(-) create mode 100644 exercise.pizzashopapi/Migrations/20250128082304_InitialCreate.Designer.cs create mode 100644 exercise.pizzashopapi/Migrations/20250128082304_InitialCreate.cs create mode 100644 exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs diff --git a/exercise.pizzashopapi/DTO/CustomerDTO.cs b/exercise.pizzashopapi/DTO/CustomerDTO.cs index 15dace4..1c5e842 100644 --- a/exercise.pizzashopapi/DTO/CustomerDTO.cs +++ b/exercise.pizzashopapi/DTO/CustomerDTO.cs @@ -13,7 +13,7 @@ public CustomerDTO(Customer customer) { Id = customer.Id; Name = customer.Name; - customer.Orders.ForEach(x => Orders.Add($"{x.pizzas}")); + customer.Orders.ForEach(x => Orders.Add($"{x.pizza}")); } } } diff --git a/exercise.pizzashopapi/DTO/OrderDTO.cs b/exercise.pizzashopapi/DTO/OrderDTO.cs index 6b5b6ec..ede985d 100644 --- a/exercise.pizzashopapi/DTO/OrderDTO.cs +++ b/exercise.pizzashopapi/DTO/OrderDTO.cs @@ -8,13 +8,13 @@ public class OrderDTO public int Id { get; set; } public string customer { get; set; } - public List pizzas { get; set; } = new List(); + public string pizza { get; set; } = ""; public OrderDTO(Order order) { Id = order.Id; customer= order.customer.Name; - order.pizzas.ForEach(x=> pizzas.Add($"{x.Name} {x.Price}")); + pizza=$"{order.pizza.Name} {order.pizza.Price}"; } } diff --git a/exercise.pizzashopapi/DTO/PizzaDTO.cs b/exercise.pizzashopapi/DTO/PizzaDTO.cs index 9b21e97..3cf26a0 100644 --- a/exercise.pizzashopapi/DTO/PizzaDTO.cs +++ b/exercise.pizzashopapi/DTO/PizzaDTO.cs @@ -14,7 +14,7 @@ public PizzaDTO(Pizza pizza) Id = pizza.Id; Name = pizza.Name; Price = pizza.Price; - pizza.Orders.ForEach(x => Orders.Add($"{x.pizzas} {x.customer}")); + pizza.Orders.ForEach(x => Orders.Add($"{x.pizza} {x.customer}")); } } diff --git a/exercise.pizzashopapi/Data/DataContext.cs b/exercise.pizzashopapi/Data/DataContext.cs index 9e96f96..26173da 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -6,7 +6,7 @@ namespace exercise.pizzashopapi.Data public class DataContext : DbContext { private string connectionString; - public DataContext(DbContextOptions options) : base(options) +public DataContext() { var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); connectionString = configuration.GetValue("ConnectionStrings:DefaultConnectionString")!; @@ -41,17 +41,19 @@ protected override async void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity() .HasMany(a => a.Orders) - .WithMany(a => a.pizzas); - + .WithOne(a => a.pizza); + modelBuilder.Entity() - .HasMany(a => a.pizzas) - .WithMany(a => a.Orders); + .HasOne(a => a.pizza) + .WithMany(a => a.Orders) + .HasForeignKey(a => a.pizzaId); modelBuilder.Entity() .HasOne(a => a.customer) - .WithMany(a => a.Orders); + .WithMany(a => a.Orders) + .HasForeignKey(a => a.customerId); //seeding diff --git a/exercise.pizzashopapi/Data/Seeder.cs b/exercise.pizzashopapi/Data/Seeder.cs index f87fbef..d078f20 100644 --- a/exercise.pizzashopapi/Data/Seeder.cs +++ b/exercise.pizzashopapi/Data/Seeder.cs @@ -20,10 +20,17 @@ public async static void SeedPizzaShopApi(this WebApplication app) db.Add(new Pizza() { Name = "Vegan Cheese Tastic" }); await db.SaveChangesAsync(); + } + if (!db.Orders.Any()) + { + db.Add(new Order() { customerId=1, pizzaId=1 }); + db.Add(new Order() { customerId = 2, pizzaId = 2 }); + await db.SaveChangesAsync(); + } //order data - if(1==1) + if (1==1) { await db.SaveChangesAsync(); diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index 46e5059..cc6bf02 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -12,6 +12,10 @@ public static void ConfigurePizzaShopApi(this WebApplication app) var pizzaGroup = app.MapGroup("pizzashop"); pizzaGroup.MapGet("/GetOrdersByCustomer", GetOrdersByCustomer); + pizzaGroup.MapGet("/Orders", GetOrders); + pizzaGroup.MapGet("/GetPizzas", GetPizzas); + pizzaGroup.MapGet("/Customers", GetCustomers); + pizzaGroup.MapGet("/Customer", GetCustomer); } @@ -24,5 +28,37 @@ public static async Task GetOrdersByCustomer(IRepository repo, int cust orders.ToList().ForEach(x => orderDTOs.Add(new OrderDTO(x))); return TypedResults.Ok(orderDTOs); } + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetOrders(IRepository repo) + { + var orders = await repo.GetOrders(); + //make it into DTO + List orderDTOs = new List(); + orders.ToList().ForEach(x => orderDTOs.Add(new OrderDTO(x))); + return TypedResults.Ok(orderDTOs); + } + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetPizzas(IRepository repo) + { + var pizzas = await repo.GetPizzas(); + List pizzaDTOs = new List(); + pizzas.ToList().ForEach(x => pizzaDTOs.Add(new PizzaDTO(x))); + return TypedResults.Ok(pizzaDTOs); + } + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetCustomers(IRepository repo) + { + var customers = await repo.GetCustomers(); + List customerDTOs = new List(); + customers.ToList().ForEach( x => customerDTOs.Add(new CustomerDTO(x))); + return TypedResults.Ok(customerDTOs); + } + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetCustomer(IRepository repo ,int id) + { + var customer = await repo.GetCustomer(id); + return TypedResults.Ok(new CustomerDTO(customer.First())); + } + } } diff --git a/exercise.pizzashopapi/Migrations/20250128082304_InitialCreate.Designer.cs b/exercise.pizzashopapi/Migrations/20250128082304_InitialCreate.Designer.cs new file mode 100644 index 0000000..f54d09c --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250128082304_InitialCreate.Designer.cs @@ -0,0 +1,126 @@ +// +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("20250128082304_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.11") + .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("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") + .HasColumnName("CustomerId"); + + b.Property("pizzaId") + .HasColumnType("integer") + .HasColumnName("PizzaId"); + + 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("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("Orders") + .HasForeignKey("pizzaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("customer"); + + b.Navigation("pizza"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Navigation("Orders"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250128082304_InitialCreate.cs b/exercise.pizzashopapi/Migrations/20250128082304_InitialCreate.cs new file mode 100644 index 0000000..7841350 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250128082304_InitialCreate.cs @@ -0,0 +1,91 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class InitialCreate : 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), + 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), + 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..d1e119f --- /dev/null +++ b/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs @@ -0,0 +1,123 @@ +// +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", "7.0.11") + .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("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") + .HasColumnName("CustomerId"); + + b.Property("pizzaId") + .HasColumnType("integer") + .HasColumnName("PizzaId"); + + 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("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("Orders") + .HasForeignKey("pizzaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("customer"); + + b.Navigation("pizza"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Navigation("Orders"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index d4847f0..4011736 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -11,7 +11,11 @@ public class Order public int Id { get; set; } [Column("Customer")] public Customer customer {get; set;} - [Column("Pizzas")] - public List pizzas {get; set;} + [Column("CustomerId")] + public int customerId { get; set; } + [Column("PizzaId")] + public int pizzaId { get; set; } + [Column("Pizzas")] + public Pizza pizza {get; set;} } } diff --git a/exercise.pizzashopapi/Repository/IRepository.cs b/exercise.pizzashopapi/Repository/IRepository.cs index 74e3a69..325dd9a 100644 --- a/exercise.pizzashopapi/Repository/IRepository.cs +++ b/exercise.pizzashopapi/Repository/IRepository.cs @@ -5,8 +5,10 @@ namespace exercise.pizzashopapi.Repository public interface IRepository { public Task> GetOrdersByCustomer(int id); - - + public Task> GetOrders(); + public Task> GetPizzas(); + public Task> GetCustomers(); + public Task> GetCustomer(int id); } } diff --git a/exercise.pizzashopapi/Repository/Repository.cs b/exercise.pizzashopapi/Repository/Repository.cs index 6ade84e..1160310 100644 --- a/exercise.pizzashopapi/Repository/Repository.cs +++ b/exercise.pizzashopapi/Repository/Repository.cs @@ -13,9 +13,32 @@ public Repository(DataContext db) } public async Task> GetOrdersByCustomer(int id) { - List orders = await _db.Orders.Include(a => a.customer).Include(b => b.pizzas).ToListAsync(); - var order = orders.FindAll(a => a.Id == id); + List orders = await _db.Orders.Include(a => a.customer).Include(b => b.pizza).ToListAsync(); + var order = orders.FindAll(a => a.customerId == id); return order; } + public async Task> GetOrders() + { + List orders = await _db.Orders.Include(a => a.customer).Include(b => b.pizza).ToListAsync(); + return orders; + } + + public async Task> GetPizzas() + { + List pizzas = await _db.Pizzas.ToListAsync(); + return pizzas; + } + + public async Task> GetCustomers() + { + List customers = await _db.Customers.ToListAsync(); + return customers; + } + + public async Task> GetCustomer(int id) + { + List customers = await _db.Customers.ToListAsync(); + return customers.FindAll(x => x.Id == id); + } } } From 1daca7210abd14a95ce595c7a2165cb1b8fedda8 Mon Sep 17 00:00:00 2001 From: Sander Rasmussen Date: Sun, 2 Feb 2025 16:02:14 +0100 Subject: [PATCH 5/8] made repos generic and used lazyloading --- exercise.pizzashopapi/Data/DataContext.cs | 3 +- .../EndPoints/PizzaShopApi.cs | 23 ++++---- exercise.pizzashopapi/Models/Customer.cs | 2 +- exercise.pizzashopapi/Models/Order.cs | 4 +- exercise.pizzashopapi/Models/Pizza.cs | 3 +- exercise.pizzashopapi/Program.cs | 5 +- .../Repository/IRepository.cs | 19 ++++--- .../Repository/Repository.cs | 57 +++++++++++++------ .../exercise.pizzashopapi.csproj | 49 ++++++++-------- 9 files changed, 100 insertions(+), 65 deletions(-) diff --git a/exercise.pizzashopapi/Data/DataContext.cs b/exercise.pizzashopapi/Data/DataContext.cs index 26173da..1353c13 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -16,7 +16,7 @@ public DataContext() protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseNpgsql(connectionString); - + optionsBuilder.UseLazyLoadingProxies(); //set primary of order? @@ -57,6 +57,7 @@ protected override async void OnModelCreating(ModelBuilder modelBuilder) //seeding + } diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index cc6bf02..cd798b7 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -20,44 +20,45 @@ public static void ConfigurePizzaShopApi(this WebApplication app) } [ProducesResponseType(StatusCodes.Status200OK)] - public static async Task GetOrdersByCustomer(IRepository repo, int customerId) + public static async Task GetOrdersByCustomer(IRepository repo, int customerId) { - var orders = await repo.GetOrdersByCustomer(customerId); + Customer customer = repo.GetById(customerId); + var orders = customer.Orders.ToList(); //make it into DTO List orderDTOs = new List(); orders.ToList().ForEach(x => orderDTOs.Add(new OrderDTO(x))); return TypedResults.Ok(orderDTOs); } [ProducesResponseType(StatusCodes.Status200OK)] - public static async Task GetOrders(IRepository repo) + public static async Task GetOrders(IRepository repo) { - var orders = await repo.GetOrders(); + var orders = repo.GetAll(); //make it into DTO List orderDTOs = new List(); orders.ToList().ForEach(x => orderDTOs.Add(new OrderDTO(x))); return TypedResults.Ok(orderDTOs); } [ProducesResponseType(StatusCodes.Status200OK)] - public static async Task GetPizzas(IRepository repo) + public static async Task GetPizzas(IRepository repo) { - var pizzas = await repo.GetPizzas(); + var pizzas = repo.GetAll(); List pizzaDTOs = new List(); pizzas.ToList().ForEach(x => pizzaDTOs.Add(new PizzaDTO(x))); return TypedResults.Ok(pizzaDTOs); } [ProducesResponseType(StatusCodes.Status200OK)] - public static async Task GetCustomers(IRepository repo) + public static async Task GetCustomers(IRepository repo) { - var customers = await repo.GetCustomers(); + var customers = repo.GetAll(); List customerDTOs = new List(); customers.ToList().ForEach( x => customerDTOs.Add(new CustomerDTO(x))); return TypedResults.Ok(customerDTOs); } [ProducesResponseType(StatusCodes.Status200OK)] - public static async Task GetCustomer(IRepository repo ,int id) + public static async Task GetCustomer(IRepository repo ,int id) { - var customer = await repo.GetCustomer(id); - return TypedResults.Ok(new CustomerDTO(customer.First())); + var customer = repo.GetById(id); + return TypedResults.Ok(new CustomerDTO(customer)); } } diff --git a/exercise.pizzashopapi/Models/Customer.cs b/exercise.pizzashopapi/Models/Customer.cs index 9c8c4d8..e856e3f 100644 --- a/exercise.pizzashopapi/Models/Customer.cs +++ b/exercise.pizzashopapi/Models/Customer.cs @@ -12,7 +12,7 @@ public class Customer [Column("Name")] public string Name { get; set; } [Column("Orders")] - public List Orders { get; set; } = new List(); + public virtual List Orders { get; set; } = new List(); } } diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index 4011736..aebd2c9 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -10,12 +10,12 @@ public class Order [Column("Id")] public int Id { get; set; } [Column("Customer")] - public Customer customer {get; set;} + public virtual Customer customer {get; set;} [Column("CustomerId")] public int customerId { get; set; } [Column("PizzaId")] public int pizzaId { get; set; } [Column("Pizzas")] - public Pizza pizza {get; set;} + public virtual Pizza pizza {get; set;} } } diff --git a/exercise.pizzashopapi/Models/Pizza.cs b/exercise.pizzashopapi/Models/Pizza.cs index 293e51e..4021ca0 100644 --- a/exercise.pizzashopapi/Models/Pizza.cs +++ b/exercise.pizzashopapi/Models/Pizza.cs @@ -13,7 +13,8 @@ public class Pizza public string Name { get; set; } [Column("Price")] public decimal Price { get; set; } + [NotMapped] - public List Orders { get; set; } = new List(); + public virtual List Orders { get; set; } = new List(); } } \ No newline at end of file diff --git a/exercise.pizzashopapi/Program.cs b/exercise.pizzashopapi/Program.cs index c04a440..bc33dcf 100644 --- a/exercise.pizzashopapi/Program.cs +++ b/exercise.pizzashopapi/Program.cs @@ -1,5 +1,6 @@ using exercise.pizzashopapi.Data; using exercise.pizzashopapi.EndPoints; +using exercise.pizzashopapi.Models; using exercise.pizzashopapi.Repository; var builder = WebApplication.CreateBuilder(args); @@ -7,7 +8,9 @@ // Add services to the container. builder.Services.AddControllers(); -builder.Services.AddScoped(); +builder.Services.AddScoped, Repository>(); +builder.Services.AddScoped, Repository>(); +builder.Services.AddScoped, Repository>(); builder.Services.AddDbContext(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); diff --git a/exercise.pizzashopapi/Repository/IRepository.cs b/exercise.pizzashopapi/Repository/IRepository.cs index 325dd9a..021373a 100644 --- a/exercise.pizzashopapi/Repository/IRepository.cs +++ b/exercise.pizzashopapi/Repository/IRepository.cs @@ -1,14 +1,19 @@ -using exercise.pizzashopapi.Models; +using System.Linq.Expressions; +using exercise.pizzashopapi.Models; +using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Repository { - public interface IRepository + public interface IRepository where T : class { - public Task> GetOrdersByCustomer(int id); - public Task> GetOrders(); - public Task> GetPizzas(); - public Task> GetCustomers(); - public Task> GetCustomer(int id); + public IEnumerable GetAll(); + IEnumerable GetAll(params Expression>[] includeExpressions); + T GetById(object id); + void Insert(T obj); + void Update(T obj); + void Delete(object id); + void Save(); + DbSet Table { get; } } } diff --git a/exercise.pizzashopapi/Repository/Repository.cs b/exercise.pizzashopapi/Repository/Repository.cs index 1160310..2e0d995 100644 --- a/exercise.pizzashopapi/Repository/Repository.cs +++ b/exercise.pizzashopapi/Repository/Repository.cs @@ -1,44 +1,65 @@ -using exercise.pizzashopapi.Data; +using System.Linq.Expressions; +using exercise.pizzashopapi.Data; using exercise.pizzashopapi.Models; using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Repository { - public class Repository : IRepository + public class Repository : IRepository where T : class { + + private DataContext _db; + private DbSet _table = null; + public Repository(DataContext db) { _db = db; + _table = _db.Set(); } - public async Task> GetOrdersByCustomer(int id) + + public IEnumerable GetAll(params Expression>[] includeExpressions) { - List orders = await _db.Orders.Include(a => a.customer).Include(b => b.pizza).ToListAsync(); - var order = orders.FindAll(a => a.customerId == id); - return order; + if (includeExpressions.Any()) + { + var set = includeExpressions + .Aggregate>, IQueryable> + (_table, (current, expression) => current.Include(expression)); + } + return _table.ToList(); } - public async Task> GetOrders() + + public IEnumerable GetAll() { - List orders = await _db.Orders.Include(a => a.customer).Include(b => b.pizza).ToListAsync(); - return orders; + return _table.ToList(); + } + public T GetById(object id) + { + return _table.Find(id); } - public async Task> GetPizzas() + public void Insert(T obj) + { + _table.Add(obj); + } + public void Update(T obj) { - List pizzas = await _db.Pizzas.ToListAsync(); - return pizzas; + _table.Attach(obj); + _db.Entry(obj).State = EntityState.Modified; } - public async Task> GetCustomers() + public void Delete(object id) { - List customers = await _db.Customers.ToListAsync(); - return customers; + T existing = _table.Find(id); + _table.Remove(existing); } - public async Task> GetCustomer(int id) + + public void Save() { - List customers = await _db.Customers.ToListAsync(); - return customers.FindAll(x => x.Id == id); + _db.SaveChanges(); } + public DbSet Table { get { return _table; } } + } } diff --git a/exercise.pizzashopapi/exercise.pizzashopapi.csproj b/exercise.pizzashopapi/exercise.pizzashopapi.csproj index 624203b..98892e1 100644 --- a/exercise.pizzashopapi/exercise.pizzashopapi.csproj +++ b/exercise.pizzashopapi/exercise.pizzashopapi.csproj @@ -1,28 +1,31 @@ - - net9.0 - enable - enable - + + net9.0 + enable + enable + api_cinema_challenge + - - - + + + + + + - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + - + \ No newline at end of file From f9b959ff652e7256d5e4a436025c0952f3d0e29a Mon Sep 17 00:00:00 2001 From: Sander Rasmussen Date: Mon, 3 Feb 2025 13:07:47 +0100 Subject: [PATCH 6/8] added extension topping --- exercise.pizzashopapi/DTO/CustomerDTO.cs | 2 +- exercise.pizzashopapi/DTO/OrderDTO.cs | 4 +- exercise.pizzashopapi/DTO/PizzaDTO.cs | 2 +- exercise.pizzashopapi/Data/DataContext.cs | 38 ++++++++++++++++--- exercise.pizzashopapi/Data/Seeder.cs | 19 +++++++++- exercise.pizzashopapi/Models/Customer.cs | 6 +-- exercise.pizzashopapi/Models/Order.cs | 9 +++-- exercise.pizzashopapi/Models/OrderToppings.cs | 22 +++++++++++ exercise.pizzashopapi/Models/Pizza.cs | 6 +-- exercise.pizzashopapi/Models/Topping.cs | 19 ++++++++++ 10 files changed, 109 insertions(+), 18 deletions(-) create mode 100644 exercise.pizzashopapi/Models/OrderToppings.cs create mode 100644 exercise.pizzashopapi/Models/Topping.cs diff --git a/exercise.pizzashopapi/DTO/CustomerDTO.cs b/exercise.pizzashopapi/DTO/CustomerDTO.cs index 1c5e842..08f76c6 100644 --- a/exercise.pizzashopapi/DTO/CustomerDTO.cs +++ b/exercise.pizzashopapi/DTO/CustomerDTO.cs @@ -11,7 +11,7 @@ public class CustomerDTO public CustomerDTO(Customer customer) { - Id = customer.Id; + Id = customer.customerId; Name = customer.Name; customer.Orders.ForEach(x => Orders.Add($"{x.pizza}")); } diff --git a/exercise.pizzashopapi/DTO/OrderDTO.cs b/exercise.pizzashopapi/DTO/OrderDTO.cs index ede985d..d63dc11 100644 --- a/exercise.pizzashopapi/DTO/OrderDTO.cs +++ b/exercise.pizzashopapi/DTO/OrderDTO.cs @@ -9,12 +9,14 @@ public class OrderDTO public int Id { get; set; } public string customer { get; set; } public string pizza { get; set; } = ""; + public List toppings { get; set; } = new List(); public OrderDTO(Order order) { - Id = order.Id; + Id = order.orderId; customer= order.customer.Name; pizza=$"{order.pizza.Name} {order.pizza.Price}"; + order.OrderToppings.ForEach(x => toppings.Add(x.topping.topping)); } } diff --git a/exercise.pizzashopapi/DTO/PizzaDTO.cs b/exercise.pizzashopapi/DTO/PizzaDTO.cs index 3cf26a0..e82f0b5 100644 --- a/exercise.pizzashopapi/DTO/PizzaDTO.cs +++ b/exercise.pizzashopapi/DTO/PizzaDTO.cs @@ -11,7 +11,7 @@ public class PizzaDTO public List Orders { get; set; } = new List(); public PizzaDTO(Pizza pizza) { - Id = pizza.Id; + Id = pizza.pizzaId; Name = pizza.Name; Price = pizza.Price; pizza.Orders.ForEach(x => Orders.Add($"{x.pizza} {x.customer}")); diff --git a/exercise.pizzashopapi/Data/DataContext.cs b/exercise.pizzashopapi/Data/DataContext.cs index 1353c13..d63b143 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -1,4 +1,5 @@ -using exercise.pizzashopapi.Models; +using api_cinema_challenge.Models; +using exercise.pizzashopapi.Models; using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Data @@ -27,17 +28,22 @@ protected override async void OnModelCreating(ModelBuilder modelBuilder) { //defining primary keys modelBuilder.Entity() - .HasKey(a => a.Id); + .HasKey(a => a.customerId); modelBuilder.Entity() - .HasKey(a => a.Id); + .HasKey(a => a.pizzaId); modelBuilder.Entity() - .HasKey(a => a.Id); + .HasKey(a => a.orderId); + modelBuilder.Entity() + .HasKey(a => a.toppingId); + modelBuilder.Entity() + .HasKey(a => a.orderToppingId); + //defining relations modelBuilder.Entity() .HasMany(a => a.Orders) .WithOne(a => a.customer) - .HasForeignKey(a => a.Id); + .HasForeignKey(a => a.customerId); modelBuilder.Entity() .HasMany(a => a.Orders) @@ -55,6 +61,25 @@ protected override async void OnModelCreating(ModelBuilder modelBuilder) .WithMany(a => a.Orders) .HasForeignKey(a => a.customerId); + modelBuilder.Entity() + .HasMany(a => a.OrderToppings) + .WithOne(a => a.order); + + + modelBuilder.Entity() + .HasOne(a => a.order) + .WithMany(a => a.OrderToppings) + .HasForeignKey(a => a.orderId); + + modelBuilder.Entity() + .HasOne(a => a.topping) + .WithMany(a => a.orderToppings) + .HasForeignKey(a => a.toppingId); + + modelBuilder.Entity() + .HasMany(a => a.orderToppings) + .WithOne(a => a.topping); + //seeding @@ -64,5 +89,8 @@ protected override async void OnModelCreating(ModelBuilder modelBuilder) public DbSet Pizzas { get; set; } public DbSet Customers { get; set; } public DbSet Orders { get; set; } + public DbSet OrderToppings { get; set; } + public DbSet Toppings { get; set; } + } } diff --git a/exercise.pizzashopapi/Data/Seeder.cs b/exercise.pizzashopapi/Data/Seeder.cs index d078f20..66ca573 100644 --- a/exercise.pizzashopapi/Data/Seeder.cs +++ b/exercise.pizzashopapi/Data/Seeder.cs @@ -1,4 +1,5 @@ -using exercise.pizzashopapi.Models; +using api_cinema_challenge.Models; +using exercise.pizzashopapi.Models; namespace exercise.pizzashopapi.Data { @@ -28,6 +29,22 @@ public async static void SeedPizzaShopApi(this WebApplication app) await db.SaveChangesAsync(); } + if (!db.Toppings.Any()) + { + db.Add(new Topping() { topping = "galic sauce" }); + db.Add(new Topping() { topping = "fish" }); + await db.SaveChangesAsync(); + + } + if (!db.OrderToppings.Any()) + { + db.Add(new OrderToppings() { orderId=1, toppingId=1 }); + db.Add(new OrderToppings() { orderId = 2, toppingId = 2 }); + await db.SaveChangesAsync(); + + } + + //order data if (1==1) diff --git a/exercise.pizzashopapi/Models/Customer.cs b/exercise.pizzashopapi/Models/Customer.cs index e856e3f..4e1f02b 100644 --- a/exercise.pizzashopapi/Models/Customer.cs +++ b/exercise.pizzashopapi/Models/Customer.cs @@ -4,11 +4,11 @@ namespace exercise.pizzashopapi.Models { [Table("Customer")] - [PrimaryKey("Id")] + [PrimaryKey("customerId")] public class Customer { - [Column("Id")] - public int Id { get; set; } + [Column("customerId")] + public int customerId { get; set; } [Column("Name")] public string Name { get; set; } [Column("Orders")] diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index aebd2c9..aa97ea1 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -1,14 +1,15 @@ using System.ComponentModel.DataAnnotations.Schema; +using api_cinema_challenge.Models; using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Models { [Table("Order")] - [PrimaryKey("Id")] + [PrimaryKey("orderId")] public class Order { - [Column("Id")] - public int Id { get; set; } + [Column("orderId")] + public int orderId { get; set; } [Column("Customer")] public virtual Customer customer {get; set;} [Column("CustomerId")] @@ -17,5 +18,7 @@ public class Order public int pizzaId { get; set; } [Column("Pizzas")] public virtual Pizza pizza {get; set;} + [NotMapped] + public virtual List OrderToppings { get; set; } } } diff --git a/exercise.pizzashopapi/Models/OrderToppings.cs b/exercise.pizzashopapi/Models/OrderToppings.cs new file mode 100644 index 0000000..97fc6e9 --- /dev/null +++ b/exercise.pizzashopapi/Models/OrderToppings.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations.Schema; +using exercise.pizzashopapi.Models; +using Microsoft.EntityFrameworkCore; + +namespace api_cinema_challenge.Models +{ + [Table("OrderToppings")] + [PrimaryKey("orderToppingId")] + public class OrderToppings + { + [Column("orderToppingId")] + public int orderToppingId { get; set; } + [Column("orderId")] + public int orderId { get; set; } + [NotMapped] + public virtual Order order { get; set; } + [Column("toppingId")] + public int toppingId { get; set; } + [NotMapped] + public virtual Topping topping { get; set; } + } +} diff --git a/exercise.pizzashopapi/Models/Pizza.cs b/exercise.pizzashopapi/Models/Pizza.cs index 4021ca0..8d02d45 100644 --- a/exercise.pizzashopapi/Models/Pizza.cs +++ b/exercise.pizzashopapi/Models/Pizza.cs @@ -4,11 +4,11 @@ namespace exercise.pizzashopapi.Models { [Table("Pizza")] - [PrimaryKey("Id")] + [PrimaryKey("pizzaId")] public class Pizza { - [Column("Id")] - public int Id { get; set; } + [Column("pizzaId")] + public int pizzaId { get; set; } [Column("Name")] public string Name { get; set; } [Column("Price")] diff --git a/exercise.pizzashopapi/Models/Topping.cs b/exercise.pizzashopapi/Models/Topping.cs new file mode 100644 index 0000000..038aa87 --- /dev/null +++ b/exercise.pizzashopapi/Models/Topping.cs @@ -0,0 +1,19 @@ + + +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; + +namespace api_cinema_challenge.Models +{ + [Table("Topping")] + [PrimaryKey("toppingId")] + public class Topping + { + [Column("toppingId")] + public int toppingId { get; set; } + [Column("topping")] + public string topping { get; set; } + [Column("orderToppings")] + public virtual List orderToppings { get; set; } + } +} From 0dddf7634730ef29e40b9fd071cd9904ac30d542 Mon Sep 17 00:00:00 2001 From: Sander Rasmussen Date: Mon, 3 Feb 2025 13:19:51 +0100 Subject: [PATCH 7/8] done with extensions --- exercise.pizzashopapi/DTO/OrderDTO.cs | 3 ++- exercise.pizzashopapi/Data/Seeder.cs | 4 ++-- .../EndPoints/PizzaShopApi.cs | 19 +++++++++++++++++++ exercise.pizzashopapi/Models/Order.cs | 10 ++++++---- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/exercise.pizzashopapi/DTO/OrderDTO.cs b/exercise.pizzashopapi/DTO/OrderDTO.cs index d63dc11..4d4a090 100644 --- a/exercise.pizzashopapi/DTO/OrderDTO.cs +++ b/exercise.pizzashopapi/DTO/OrderDTO.cs @@ -10,6 +10,7 @@ public class OrderDTO public string customer { get; set; } public string pizza { get; set; } = ""; public List toppings { get; set; } = new List(); + public string status { get; set; } public OrderDTO(Order order) { @@ -17,7 +18,7 @@ public OrderDTO(Order order) customer= order.customer.Name; pizza=$"{order.pizza.Name} {order.pizza.Price}"; order.OrderToppings.ForEach(x => toppings.Add(x.topping.topping)); - + status = order.status; } } } diff --git a/exercise.pizzashopapi/Data/Seeder.cs b/exercise.pizzashopapi/Data/Seeder.cs index 66ca573..b0ebb55 100644 --- a/exercise.pizzashopapi/Data/Seeder.cs +++ b/exercise.pizzashopapi/Data/Seeder.cs @@ -24,8 +24,8 @@ public async static void SeedPizzaShopApi(this WebApplication app) } if (!db.Orders.Any()) { - db.Add(new Order() { customerId=1, pizzaId=1 }); - db.Add(new Order() { customerId = 2, pizzaId = 2 }); + db.Add(new Order() { customerId=1, pizzaId=1 , status="On the road"}); + db.Add(new Order() { customerId = 2, pizzaId = 2 , status="prepearing"}); await db.SaveChangesAsync(); } diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index cd798b7..55dfe7c 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -16,9 +16,28 @@ public static void ConfigurePizzaShopApi(this WebApplication app) pizzaGroup.MapGet("/GetPizzas", GetPizzas); pizzaGroup.MapGet("/Customers", GetCustomers); pizzaGroup.MapGet("/Customer", GetCustomer); + pizzaGroup.MapPut("/Order/status", SetOrderStatus); } + + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public static async Task SetOrderStatus(IRepository repo, int orderId, string status) + { + try + { + Order order = repo.GetById(orderId); + order.status = status; + repo.Save(); + return TypedResults.Ok(); + } + catch (Exception ex) + { + return TypedResults.BadRequest(ex); + } + } + [ProducesResponseType(StatusCodes.Status200OK)] public static async Task GetOrdersByCustomer(IRepository repo, int customerId) { diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index aa97ea1..232b393 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -11,14 +11,16 @@ public class Order [Column("orderId")] public int orderId { get; set; } [Column("Customer")] - public virtual Customer customer {get; set;} + public virtual Customer customer { get; set; } [Column("CustomerId")] - public int customerId { get; set; } + public int customerId { get; set; } [Column("PizzaId")] public int pizzaId { get; set; } - [Column("Pizzas")] - public virtual Pizza pizza {get; set;} + [Column("Pizzas")] + public virtual Pizza pizza { get; set; } [NotMapped] public virtual List OrderToppings { get; set; } + [Column("status")] + public string status { get; set; } } } From e6da37f987de66654d0879cae75dd37fb223a1d5 Mon Sep 17 00:00:00 2001 From: Sander Rasmussen Date: Mon, 3 Feb 2025 13:38:05 +0100 Subject: [PATCH 8/8] core and extension --- exercise.pizzashopapi/DTO/CustomerDTO.cs | 2 +- .../EndPoints/PizzaShopApi.cs | 61 ++++++++++++++++++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/exercise.pizzashopapi/DTO/CustomerDTO.cs b/exercise.pizzashopapi/DTO/CustomerDTO.cs index 08f76c6..6104543 100644 --- a/exercise.pizzashopapi/DTO/CustomerDTO.cs +++ b/exercise.pizzashopapi/DTO/CustomerDTO.cs @@ -13,7 +13,7 @@ public CustomerDTO(Customer customer) { Id = customer.customerId; Name = customer.Name; - customer.Orders.ForEach(x => Orders.Add($"{x.pizza}")); + customer.Orders.ForEach(x => Orders.Add($"{x.pizza.Name}")); } } } diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index 55dfe7c..083092c 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -1,4 +1,6 @@ -using exercise.pizzashopapi.DTO; +using api_cinema_challenge.Models; +using System.ComponentModel.DataAnnotations.Schema; +using exercise.pizzashopapi.DTO; using exercise.pizzashopapi.Models; using exercise.pizzashopapi.Repository; using Microsoft.AspNetCore.Mvc; @@ -10,17 +12,70 @@ public static class PizzaShopApi public static void ConfigurePizzaShopApi(this WebApplication app) { var pizzaGroup = app.MapGroup("pizzashop"); - + + //gets pizzaGroup.MapGet("/GetOrdersByCustomer", GetOrdersByCustomer); pizzaGroup.MapGet("/Orders", GetOrders); pizzaGroup.MapGet("/GetPizzas", GetPizzas); pizzaGroup.MapGet("/Customers", GetCustomers); pizzaGroup.MapGet("/Customer", GetCustomer); + //sets pizzaGroup.MapPut("/Order/status", SetOrderStatus); - + //creates + pizzaGroup.MapPost("/neworder", CreateOrder); + pizzaGroup.MapPost("/newcustomer", CreateCustomer); + pizzaGroup.MapPost("/newpizza", CreatePizza); } + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public static async Task CreateOrder(IRepository repo, int customerId, int pizzaId, string status ) + { + try + { + Order order = new Order { status = status , customerId= customerId, pizzaId=pizzaId}; + repo.Insert(order); + repo.Save(); + return TypedResults.Ok(); + } + catch (Exception ex) + { + return TypedResults.BadRequest(ex); + } + } + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public static async Task CreatePizza(IRepository repo, decimal price, string name) + { + try + { + Pizza pizza = new Pizza { Price=price, Name=name}; + repo.Insert(pizza); + repo.Save(); + return TypedResults.Ok(); + } + catch (Exception ex) + { + return TypedResults.BadRequest(ex); + } + } + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public static async Task CreateCustomer(IRepository repo, string name) + { + try + { + Customer customer = new Customer { Name=name }; + repo.Insert(customer); + repo.Save(); + return TypedResults.Ok(); + } + catch (Exception ex) + { + return TypedResults.BadRequest(ex); + } + } [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public static async Task SetOrderStatus(IRepository repo, int orderId, string status)