diff --git a/exercise.pizzashopapi/DTOs/CustomerDTOs.cs b/exercise.pizzashopapi/DTOs/CustomerDTOs.cs new file mode 100644 index 0000000..b41ef7d --- /dev/null +++ b/exercise.pizzashopapi/DTOs/CustomerDTOs.cs @@ -0,0 +1,10 @@ +using System; + +namespace exercise.pizzashopapi.DTOs; + +public class CustomerDTO +{ + public int Id { get; set; } + public string Name { get; set; } + +} diff --git a/exercise.pizzashopapi/DTOs/OrderDTOs.cs b/exercise.pizzashopapi/DTOs/OrderDTOs.cs new file mode 100644 index 0000000..311b8cb --- /dev/null +++ b/exercise.pizzashopapi/DTOs/OrderDTOs.cs @@ -0,0 +1,21 @@ +using System; + +namespace exercise.pizzashopapi.DTOs; + +public class OrderDTO +{ + public int Id { get; set; } + public CustomerDTO Customer { get; set; } + public PizzaDTO Pizza { get; set; } + public List OrderToppings { get; set; } + + +} + + +public class CreateOrderDTO +{ + public int CustomerId { get; set; } + public int PizzaId { get; set; } + public List Toppings { get; set; } +} \ No newline at end of file diff --git a/exercise.pizzashopapi/DTOs/OrderToppingDTO.cs b/exercise.pizzashopapi/DTOs/OrderToppingDTO.cs new file mode 100644 index 0000000..53e05b2 --- /dev/null +++ b/exercise.pizzashopapi/DTOs/OrderToppingDTO.cs @@ -0,0 +1,10 @@ +using System; + +namespace exercise.pizzashopapi.DTOs; + +public class OrderToppingDTO +{ + public ToppingDTO Topping { get; set; } + + +} diff --git a/exercise.pizzashopapi/DTOs/PizzaDTOs.cs b/exercise.pizzashopapi/DTOs/PizzaDTOs.cs new file mode 100644 index 0000000..2c93ee0 --- /dev/null +++ b/exercise.pizzashopapi/DTOs/PizzaDTOs.cs @@ -0,0 +1,12 @@ +using System; + +namespace exercise.pizzashopapi.DTOs; + +public class PizzaDTO +{ + public int Id { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } +} \ No newline at end of file diff --git a/exercise.pizzashopapi/DTOs/ToppingDTOs.cs b/exercise.pizzashopapi/DTOs/ToppingDTOs.cs new file mode 100644 index 0000000..9571367 --- /dev/null +++ b/exercise.pizzashopapi/DTOs/ToppingDTOs.cs @@ -0,0 +1,11 @@ +using System; +using Microsoft.Extensions.Diagnostics.HealthChecks; + +namespace exercise.pizzashopapi.DTOs; + +public class ToppingDTO +{ + + public string Name { get; set; } + public decimal Price {get;set;} +} diff --git a/exercise.pizzashopapi/Data/DataContext.cs b/exercise.pizzashopapi/Data/DataContext.cs index 129199e..7f1643f 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -5,24 +5,94 @@ namespace exercise.pizzashopapi.Data { public class DataContext : DbContext { - private string connectionString; + private string _connectionString; public DataContext() { var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); - connectionString = configuration.GetValue("ConnectionStrings:DefaultConnectionString"); + _connectionString = configuration.GetValue("ConnectionStrings:DefaultConnection"); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseNpgsql(connectionString); + optionsBuilder.UseNpgsql(_connectionString); + optionsBuilder.UseLazyLoadingProxies(); //set primary of order? //seed data? + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasKey(p => p.Id); + modelBuilder.Entity().HasKey(c => c.Id); + modelBuilder.Entity().HasKey(o => o.Id); + modelBuilder.Entity().HasKey(t => t.Id); + modelBuilder.Entity().HasKey(ot => ot.Id); + + modelBuilder.Entity() + .HasMany(c => c.Orders) + .WithOne(o => o.Customer); + + modelBuilder.Entity() + .HasOne(o => o.Customer) + .WithMany(c => c.Orders) + .HasForeignKey(o => o.CustomerId); + + modelBuilder.Entity() + .HasOne(o => o.Pizza) + .WithMany(p => p.Orders) + .HasForeignKey(o => o.PizzaId); + + modelBuilder.Entity() + .HasMany(o => o.OrderToppings) + .WithOne(ot => ot.Order) + .HasForeignKey(ot => ot.OrderId); + + modelBuilder.Entity() + .HasMany(p => p.Orders) + .WithOne(o => o.Pizza); + + modelBuilder.Entity() + .HasOne(ot => ot.Order) + .WithMany(o => o.OrderToppings) + .HasForeignKey(ot => ot.OrderId); + + modelBuilder.Entity() + .HasOne(ot => ot.Topping) + .WithMany(t => t.OrderToppings) + .HasForeignKey(ot => ot.ToppingId); + + modelBuilder.Entity() + .HasMany(o => o.OrderToppings) + .WithOne(ot => ot.Order); + + DateTime exampleDate = new DateTime(2021, 1, 1, 0, 0, 0, DateTimeKind.Utc); + //Seed pizza, customers and Toppings + modelBuilder.Entity().HasData( + new Pizza { Id = 1, Name = "Pepperoni", Price = 10.00m, CreatedAt = exampleDate, UpdatedAt = exampleDate }, + new Pizza { Id = 2, Name = "Cheese", Price = 8.00m, CreatedAt = exampleDate, UpdatedAt = exampleDate }, + new Pizza { Id = 3, Name = "Mushrooms", Price = 9.00m, CreatedAt = exampleDate, UpdatedAt = exampleDate } + ); + + + modelBuilder.Entity().HasData( + new Customer { Id = 1, Name = "John Doe", CreatedAt = exampleDate, UpdatedAt = exampleDate }, + new Customer { Id = 2, Name = "Jane Doe", CreatedAt = exampleDate, UpdatedAt = exampleDate } + ); + modelBuilder.Entity().HasData( + new Topping { Id = 1, Price = 5, Name = "Pepperoni", CreatedAt = exampleDate, UpdatedAt = exampleDate }, + new Topping { Id = 2, Price = 6, Name = "Cheese", CreatedAt = exampleDate, UpdatedAt = exampleDate }, + new Topping { Id = 3, Price = 7, Name = "Mushrooms", CreatedAt = exampleDate, UpdatedAt = exampleDate } + + ); + } public DbSet Pizzas { get; set; } public DbSet Customers { get; set; } public DbSet Orders { get; set; } + public DbSet Toppings {get;set;} + public DbSet OrderToppings {get;set;} } } diff --git a/exercise.pizzashopapi/Data/Seeder.cs b/exercise.pizzashopapi/Data/Seeder.cs deleted file mode 100644 index f87fbef..0000000 --- a/exercise.pizzashopapi/Data/Seeder.cs +++ /dev/null @@ -1,34 +0,0 @@ -using exercise.pizzashopapi.Models; - -namespace exercise.pizzashopapi.Data -{ - public static class Seeder - { - public async static void SeedPizzaShopApi(this WebApplication app) - { - using(var db = new DataContext()) - { - if(!db.Customers.Any()) - { - db.Add(new Customer() { Name="Nigel" }); - db.Add(new Customer() { Name = "Dave" }); - await db.SaveChangesAsync(); - } - if(!db.Pizzas.Any()) - { - db.Add(new Pizza() { Name = "Cheese & Pineapple" }); - db.Add(new Pizza() { Name = "Vegan Cheese Tastic" }); - await db.SaveChangesAsync(); - - } - - //order data - if(1==1) - { - - await db.SaveChangesAsync(); - } - } - } - } -} diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index f8be2b0..326d6d4 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -1,4 +1,7 @@ -using exercise.pizzashopapi.Repository; +using AutoMapper; +using exercise.pizzashopapi.DTOs; +using exercise.pizzashopapi.Models; +using exercise.pizzashopapi.Repository; using Microsoft.AspNetCore.Mvc; namespace exercise.pizzashopapi.EndPoints @@ -7,9 +10,79 @@ public static class PizzaShopApi { public static void ConfigurePizzaShopApi(this WebApplication app) { + var pizza = app.MapGroup("/pizzas"); + + pizza.MapGet("", GetPizzas); + pizza.MapGet("/orders/{id}", GetOrdersById); + pizza.MapPost("/orders", CreateOrder); + + } + #region PizzaEndpoints + + public static async Task GetPizzas(IRepository pizzaRepository, IMapper mapper) + { + var pizzas = await pizzaRepository.GetAll(); + return Results.Ok(mapper.Map>(pizzas)); + } + + + #endregion + + #region ToppingEndpoints + + public static async Task GetToppings(IRepository toppingRepository, IMapper mapper) + { + var toppings = await toppingRepository.GetAll(); + return Results.Ok(mapper.Map>(toppings)); + } + + #endregion + + #region OrderEndpoints + + public static async Task GetOrders(IRepository orderRepository, IMapper mapper) + { + var orders = await orderRepository.GetAll(); + return Results.Ok(mapper.Map>(orders)); + } + public static async Task GetOrdersById(IRepository orderRepository, int id, IMapper mapper) + { + var orders = await orderRepository.GetAll(); + orders = orders.Where(o => o.CustomerId == id); + return Results.Ok(mapper.Map>(orders)); + } + + public static async Task CreateOrder(IRepository orderRepository, CreateOrderDTO orderDTO, IMapper mapper) + { + Order order = new Order() + { + CustomerId = orderDTO.CustomerId, + PizzaId = orderDTO.PizzaId + }; + List orderToppings = new List(); + foreach (var topping in orderDTO.Toppings) + { + orderToppings.Add(new OrderToppings() + { + ToppingId = topping + }); + } + order.OrderToppings = orderToppings; + + + + var newOrder = await orderRepository.CreateEntity(order); + return Results.Ok("Order created!"); + + } + + + + #endregion + } } diff --git a/exercise.pizzashopapi/Migrations/20250203122824_secondMigrations.Designer.cs b/exercise.pizzashopapi/Migrations/20250203122824_secondMigrations.Designer.cs new file mode 100644 index 0000000..d25eca1 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250203122824_secondMigrations.Designer.cs @@ -0,0 +1,289 @@ +// +using System; +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("20250203122824_secondMigrations")] + partial class secondMigrations + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Customers"); + + b.HasData( + new + { + Id = 1, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "John Doe", + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 2, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Jane Doe", + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("OrderToppingsId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.OrderToppings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("OrderId") + .HasColumnType("integer"); + + b.Property("ToppingId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("ToppingId"); + + b.ToTable("OrderToppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Pizzas"); + + b.HasData( + new + { + Id = 1, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Pepperoni", + Price = 10.00m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 2, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Cheese", + Price = 8.00m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 3, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Mushrooms", + Price = 9.00m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Topping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Toppings"); + + b.HasData( + new + { + Id = 1, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Pepperoni", + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 2, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Cheese", + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 3, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Mushrooms", + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }); + }); + + 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.OrderToppings", b => + { + b.HasOne("exercise.pizzashopapi.Models.Order", "Order") + .WithMany("OrderToppings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Topping", "Topping") + .WithMany("OrderToppings") + .HasForeignKey("ToppingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + + b.Navigation("Topping"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Navigation("OrderToppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Topping", b => + { + b.Navigation("OrderToppings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250203122824_secondMigrations.cs b/exercise.pizzashopapi/Migrations/20250203122824_secondMigrations.cs new file mode 100644 index 0000000..6048b98 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250203122824_secondMigrations.cs @@ -0,0 +1,189 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class secondMigrations : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Customers", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Customers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Pizzas", + 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), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Pizzas", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Toppings", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Toppings", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Orders", + 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), + OrderToppingsId = table.Column(type: "integer", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Orders", x => x.Id); + table.ForeignKey( + name: "FK_Orders_Customers_CustomerId", + column: x => x.CustomerId, + principalTable: "Customers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Orders_Pizzas_PizzaId", + column: x => x.PizzaId, + principalTable: "Pizzas", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "OrderToppings", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + OrderId = table.Column(type: "integer", nullable: false), + ToppingId = table.Column(type: "integer", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_OrderToppings", x => x.Id); + table.ForeignKey( + name: "FK_OrderToppings_Orders_OrderId", + column: x => x.OrderId, + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_OrderToppings_Toppings_ToppingId", + column: x => x.ToppingId, + principalTable: "Toppings", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.InsertData( + table: "Customers", + columns: new[] { "Id", "CreatedAt", "Name", "UpdatedAt" }, + values: new object[,] + { + { 1, new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "John Doe", new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) }, + { 2, new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "Jane Doe", new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) } + }); + + migrationBuilder.InsertData( + table: "Pizzas", + columns: new[] { "Id", "CreatedAt", "Name", "Price", "UpdatedAt" }, + values: new object[,] + { + { 1, new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "Pepperoni", 10.00m, new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) }, + { 2, new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "Cheese", 8.00m, new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) }, + { 3, new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "Mushrooms", 9.00m, new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) } + }); + + migrationBuilder.InsertData( + table: "Toppings", + columns: new[] { "Id", "CreatedAt", "Name", "UpdatedAt" }, + values: new object[,] + { + { 1, new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "Pepperoni", new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) }, + { 2, new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "Cheese", new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) }, + { 3, new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "Mushrooms", new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) } + }); + + migrationBuilder.CreateIndex( + name: "IX_Orders_CustomerId", + table: "Orders", + column: "CustomerId"); + + migrationBuilder.CreateIndex( + name: "IX_Orders_PizzaId", + table: "Orders", + column: "PizzaId"); + + migrationBuilder.CreateIndex( + name: "IX_OrderToppings_OrderId", + table: "OrderToppings", + column: "OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_OrderToppings_ToppingId", + table: "OrderToppings", + column: "ToppingId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "OrderToppings"); + + migrationBuilder.DropTable( + name: "Orders"); + + migrationBuilder.DropTable( + name: "Toppings"); + + migrationBuilder.DropTable( + name: "Customers"); + + migrationBuilder.DropTable( + name: "Pizzas"); + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250203124057_secondMigrations2.Designer.cs b/exercise.pizzashopapi/Migrations/20250203124057_secondMigrations2.Designer.cs new file mode 100644 index 0000000..e1d097f --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250203124057_secondMigrations2.Designer.cs @@ -0,0 +1,295 @@ +// +using System; +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("20250203124057_secondMigrations2")] + partial class secondMigrations2 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Customers"); + + b.HasData( + new + { + Id = 1, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "John Doe", + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 2, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Jane Doe", + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("OrderToppingsId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.OrderToppings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("OrderId") + .HasColumnType("integer"); + + b.Property("ToppingId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("ToppingId"); + + b.ToTable("OrderToppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Pizzas"); + + b.HasData( + new + { + Id = 1, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Pepperoni", + Price = 10.00m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 2, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Cheese", + Price = 8.00m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 3, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Mushrooms", + Price = 9.00m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Topping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Toppings"); + + b.HasData( + new + { + Id = 1, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Pepperoni", + Price = 5m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 2, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Cheese", + Price = 6m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 3, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Mushrooms", + Price = 7m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }); + }); + + 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.OrderToppings", b => + { + b.HasOne("exercise.pizzashopapi.Models.Order", "Order") + .WithMany("OrderToppings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Topping", "Topping") + .WithMany("OrderToppings") + .HasForeignKey("ToppingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + + b.Navigation("Topping"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Navigation("OrderToppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Topping", b => + { + b.Navigation("OrderToppings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250203124057_secondMigrations2.cs b/exercise.pizzashopapi/Migrations/20250203124057_secondMigrations2.cs new file mode 100644 index 0000000..3e3e652 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250203124057_secondMigrations2.cs @@ -0,0 +1,50 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class secondMigrations2 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Price", + table: "Toppings", + type: "numeric", + nullable: false, + defaultValue: 0m); + + migrationBuilder.UpdateData( + table: "Toppings", + keyColumn: "Id", + keyValue: 1, + column: "Price", + value: 5m); + + migrationBuilder.UpdateData( + table: "Toppings", + keyColumn: "Id", + keyValue: 2, + column: "Price", + value: 6m); + + migrationBuilder.UpdateData( + table: "Toppings", + keyColumn: "Id", + keyValue: 3, + column: "Price", + value: 7m); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Price", + table: "Toppings"); + } + } +} diff --git a/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs b/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs new file mode 100644 index 0000000..8efb586 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs @@ -0,0 +1,292 @@ +// +using System; +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("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Customers"); + + b.HasData( + new + { + Id = 1, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "John Doe", + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 2, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Jane Doe", + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("OrderToppingsId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.OrderToppings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("OrderId") + .HasColumnType("integer"); + + b.Property("ToppingId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("ToppingId"); + + b.ToTable("OrderToppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Pizzas"); + + b.HasData( + new + { + Id = 1, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Pepperoni", + Price = 10.00m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 2, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Cheese", + Price = 8.00m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 3, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Mushrooms", + Price = 9.00m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Topping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Toppings"); + + b.HasData( + new + { + Id = 1, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Pepperoni", + Price = 5m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 2, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Cheese", + Price = 6m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }, + new + { + Id = 3, + CreatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + Name = "Mushrooms", + Price = 7m, + UpdatedAt = new DateTime(2021, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + }); + }); + + 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.OrderToppings", b => + { + b.HasOne("exercise.pizzashopapi.Models.Order", "Order") + .WithMany("OrderToppings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("exercise.pizzashopapi.Models.Topping", "Topping") + .WithMany("OrderToppings") + .HasForeignKey("ToppingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + + b.Navigation("Topping"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Customer", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Navigation("OrderToppings"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Pizza", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Topping", b => + { + b.Navigation("OrderToppings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/exercise.pizzashopapi/Models/Customer.cs b/exercise.pizzashopapi/Models/Customer.cs index 2ca83bd..35172a6 100644 --- a/exercise.pizzashopapi/Models/Customer.cs +++ b/exercise.pizzashopapi/Models/Customer.cs @@ -2,9 +2,21 @@ namespace exercise.pizzashopapi.Models { - public class Customer + public class Customer : IPizzaShopEntity { public int Id { get; set; } public string Name { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } + [NotMapped] + public virtual List Orders { get; set; } + [NotMapped] + public virtual List OrderToppings { get; set; } + + + public void Update(IPizzaShopEntity entity) + { + throw new NotImplementedException(); + } } } diff --git a/exercise.pizzashopapi/Models/IPizzaShopEntity.cs b/exercise.pizzashopapi/Models/IPizzaShopEntity.cs new file mode 100644 index 0000000..dddfc36 --- /dev/null +++ b/exercise.pizzashopapi/Models/IPizzaShopEntity.cs @@ -0,0 +1,12 @@ +using System; + +namespace exercise.pizzashopapi.Models; + +public interface IPizzaShopEntity +{ + public int Id {get;set;} + public DateTime CreatedAt {get;set;} + public DateTime UpdatedAt {get;set;} + + public void Update(IPizzaShopEntity entity); +} diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index fbe6113..152290b 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -2,9 +2,24 @@ namespace exercise.pizzashopapi.Models { - public class Order + public class Order : IPizzaShopEntity { - - + public int Id {get;set;} + public int CustomerId {get;set;} + public int PizzaId {get;set;} + public int OrderToppingsId {get;set;} + public DateTime CreatedAt {get;set;} + public DateTime UpdatedAt {get;set;} + [NotMapped] + public virtual Customer Customer {get;set;} + [NotMapped] + public virtual Pizza Pizza {get;set;} + [NotMapped] + public virtual List OrderToppings {get;set;} + + public void Update(IPizzaShopEntity entity) + { + throw new NotImplementedException(); + } } } diff --git a/exercise.pizzashopapi/Models/OrderToppings.cs b/exercise.pizzashopapi/Models/OrderToppings.cs new file mode 100644 index 0000000..7b609c9 --- /dev/null +++ b/exercise.pizzashopapi/Models/OrderToppings.cs @@ -0,0 +1,23 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace exercise.pizzashopapi.Models; + +public class OrderToppings : IPizzaShopEntity +{ + public int Id { get;set;} + public int OrderId {get;set;} + public int ToppingId {get;set;} + public DateTime CreatedAt { get;set;} + public DateTime UpdatedAt { get;set;} + [NotMapped] + public virtual Order Order { get;set;} + [NotMapped] + public virtual Topping Topping { get;set;} + + + public void Update(IPizzaShopEntity entity) + { + throw new NotImplementedException(); + } +} diff --git a/exercise.pizzashopapi/Models/Pizza.cs b/exercise.pizzashopapi/Models/Pizza.cs index 5c085ec..7ff6523 100644 --- a/exercise.pizzashopapi/Models/Pizza.cs +++ b/exercise.pizzashopapi/Models/Pizza.cs @@ -3,10 +3,19 @@ namespace exercise.pizzashopapi.Models { - public class Pizza + public class Pizza : IPizzaShopEntity { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } + [NotMapped] + public virtual List Orders { get; set; } + + public void Update(IPizzaShopEntity entity) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/exercise.pizzashopapi/Models/Topping.cs b/exercise.pizzashopapi/Models/Topping.cs new file mode 100644 index 0000000..71b0ee4 --- /dev/null +++ b/exercise.pizzashopapi/Models/Topping.cs @@ -0,0 +1,20 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace exercise.pizzashopapi.Models; + +public class Topping : IPizzaShopEntity +{ + public int Id { get;set; } + public string Name { get;set; } + public decimal Price { get;set; } + public DateTime CreatedAt { get;set; } + public DateTime UpdatedAt { get;set; } + [NotMapped] + public virtual List OrderToppings { get;set; } + + public void Update(IPizzaShopEntity entity) + { + throw new NotImplementedException(); + } +} diff --git a/exercise.pizzashopapi/Program.cs b/exercise.pizzashopapi/Program.cs index c04a440..19ce943 100644 --- a/exercise.pizzashopapi/Program.cs +++ b/exercise.pizzashopapi/Program.cs @@ -1,5 +1,7 @@ +using System.ComponentModel; using exercise.pizzashopapi.Data; using exercise.pizzashopapi.EndPoints; +using exercise.pizzashopapi.Models; using exercise.pizzashopapi.Repository; var builder = WebApplication.CreateBuilder(args); @@ -7,8 +9,13 @@ // 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.AddScoped, Repository>(); +builder.Services.AddScoped, Repository>(); builder.Services.AddDbContext(); +builder.Services.AddAutoMapper(typeof(Program)); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); @@ -30,6 +37,4 @@ app.ConfigurePizzaShopApi(); -app.SeedPizzaShopApi(); - app.Run(); diff --git a/exercise.pizzashopapi/Repository/IRepository.cs b/exercise.pizzashopapi/Repository/IRepository.cs index b114ea8..6ca7386 100644 --- a/exercise.pizzashopapi/Repository/IRepository.cs +++ b/exercise.pizzashopapi/Repository/IRepository.cs @@ -2,9 +2,15 @@ namespace exercise.pizzashopapi.Repository { - public interface IRepository + public interface IRepository { - Task> GetOrdersByCustomer(int id); + Task> GetAll(); + + Task GetEntityById(int id); + Task UpdateEntityById(int id, T entity); + Task CreateEntity(T entity); + Task DeleteEntityById(int id); + public bool Exists(Func exist); } diff --git a/exercise.pizzashopapi/Repository/Repository.cs b/exercise.pizzashopapi/Repository/Repository.cs index e109fce..a22111a 100644 --- a/exercise.pizzashopapi/Repository/Repository.cs +++ b/exercise.pizzashopapi/Repository/Repository.cs @@ -1,14 +1,75 @@ 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, IPizzaShopEntity { - private DataContext _db; - public Task> GetOrdersByCustomer(int id) + private DataContext _db; + private DbSet _table; + + public Repository(DataContext context) + { + _db = context; + _table = _db.Set(); + } + + + public async Task CreateEntity(T entity) + { + if (_table.Count() == 0) + entity.Id = 1; + else entity.Id = _table.Max(e => e.Id) + 1; + await _table.AddAsync(entity); + await _db.SaveChangesAsync(); + return entity; //Ensures related objects are returned aswell + } + + public async Task DeleteEntityById(int id) + { + T entity = await _table.FindAsync(id); + if (entity != null) { - throw new NotImplementedException(); + _table.Remove(entity); + await _db.SaveChangesAsync(); } + + return entity; + } + + public async Task> GetAll() + { + return await _table.ToListAsync(); + } + + //The use of "lazy loading" enables us to get all relationed entities without include + public async Task GetEntityById(int id) + { + return await _table.FindAsync(id); + } + + public async Task UpdateEntityById(int id, T entity) + { + T entityToUpdate = await _table.FindAsync(id); + + try + { + //Updates only fields that are not empty + entityToUpdate.Update(entity); + await _db.SaveChangesAsync(); + + return entityToUpdate; + } + catch (Exception) + { + return entityToUpdate; + } + } + + public bool Exists(Func exist) + { + return _table.Any(exist); + } } } diff --git a/exercise.pizzashopapi/Utility/Mappers.cs b/exercise.pizzashopapi/Utility/Mappers.cs new file mode 100644 index 0000000..29cce83 --- /dev/null +++ b/exercise.pizzashopapi/Utility/Mappers.cs @@ -0,0 +1,22 @@ +using System; +using AutoMapper; +using exercise.pizzashopapi.DTOs; +using exercise.pizzashopapi.Models; + +namespace exercise.pizzashopapi.Utility; + +public class Mappers : Profile +{ + + public Mappers() + { + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + } + + +} diff --git a/exercise.pizzashopapi/exercise.pizzashopapi.csproj b/exercise.pizzashopapi/exercise.pizzashopapi.csproj index 624203b..02844fe 100644 --- a/exercise.pizzashopapi/exercise.pizzashopapi.csproj +++ b/exercise.pizzashopapi/exercise.pizzashopapi.csproj @@ -11,18 +11,20 @@ - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + +