diff --git a/exercise.pizzashopapi/DTOs/CustomerDTO.cs b/exercise.pizzashopapi/DTOs/CustomerDTO.cs new file mode 100644 index 0000000..241dd29 --- /dev/null +++ b/exercise.pizzashopapi/DTOs/CustomerDTO.cs @@ -0,0 +1,9 @@ +namespace exercise.pizzashopapi.DTOs +{ + public class CustomerDTO + { + public int Id { get; set; } + public string Name { get; set; } + //public IEnumerable Orders { get; set; } = new List(); + } +} diff --git a/exercise.pizzashopapi/DTOs/OrderDTO.cs b/exercise.pizzashopapi/DTOs/OrderDTO.cs new file mode 100644 index 0000000..b0fe1ec --- /dev/null +++ b/exercise.pizzashopapi/DTOs/OrderDTO.cs @@ -0,0 +1,10 @@ +namespace exercise.pizzashopapi.DTOs +{ + public class OrderDTO + { + public int CustomerId { get; set; } + public int PizzaId { get; set; } + public string PizzaName { get; set; } + public string CustomerName { get; set; } + } +} diff --git a/exercise.pizzashopapi/DTOs/PizzaDTO.cs b/exercise.pizzashopapi/DTOs/PizzaDTO.cs new file mode 100644 index 0000000..7f4485c --- /dev/null +++ b/exercise.pizzashopapi/DTOs/PizzaDTO.cs @@ -0,0 +1,10 @@ +namespace exercise.pizzashopapi.DTOs +{ + public class PizzaDTO + { + public int Id { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } + //public IEnumerable Orders { get; set; } = new List(); + } +} diff --git a/exercise.pizzashopapi/Data/DataContext.cs b/exercise.pizzashopapi/Data/DataContext.cs index 129199e..380fc36 100644 --- a/exercise.pizzashopapi/Data/DataContext.cs +++ b/exercise.pizzashopapi/Data/DataContext.cs @@ -1,4 +1,5 @@ -using exercise.pizzashopapi.Models; +using System.Diagnostics; +using exercise.pizzashopapi.Models; using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Data @@ -12,11 +13,52 @@ public DataContext() connectionString = configuration.GetValue("ConnectionStrings:DefaultConnectionString"); } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + + modelBuilder.Entity().HasKey(o => new { o.CustomerId, o.PizzaId }); + modelBuilder.Entity().HasOne(o => o.Customer).WithMany(c => c.Orders).HasForeignKey(o => o.CustomerId); + modelBuilder.Entity().HasOne(p => p.Pizza).WithMany(p =>p.Orders).HasForeignKey(o => o.PizzaId); + + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().HasData( + new Customer { Id = 3, Name = "Johhny" }, + new Customer { Id = 4, Name = "Gunnar" } + ); + + modelBuilder.Entity().HasData( + new Pizza { Id = 3, Name = "Pepperoni", Price = 8.99m }, + new Pizza { Id = 4, Name = "BBQ chicken", Price = 10.99m } + ); + + modelBuilder.Entity().HasData( + new Order { CustomerId = 1, PizzaId = 2 }, + new Order { CustomerId = 2, PizzaId = 1 } + ); + + modelBuilder.Entity().HasData( + new Order { CustomerId = 3, PizzaId = 4 }, + new Order { CustomerId = 4, PizzaId = 3 } + ); + + modelBuilder.Entity().HasData( + new Customer { Id = 8, Name = "Håkon" } + ); + + modelBuilder.Entity().HasData( + new Pizza { Id = 9, Name = "Meatlover", Price = 12.99m } + ); + + } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseNpgsql(connectionString); //set primary of order? + optionsBuilder.LogTo(message => Debug.WriteLine(message)); //seed data? diff --git a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs index f8be2b0..00642a3 100644 --- a/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs +++ b/exercise.pizzashopapi/EndPoints/PizzaShopApi.cs @@ -1,4 +1,6 @@ -using exercise.pizzashopapi.Repository; +using AutoMapper; +using exercise.pizzashopapi.DTOs; +using exercise.pizzashopapi.Repository; using Microsoft.AspNetCore.Mvc; namespace exercise.pizzashopapi.EndPoints @@ -7,9 +9,40 @@ public static class PizzaShopApi { public static void ConfigurePizzaShopApi(this WebApplication app) { - + var shop = app.MapGroup("shop"); + + shop.MapGet("/orders", GetAllOrders); + shop.MapGet("/pizzas", GetAllPizzas); + shop.MapGet("/customers", GetAllCustomers); + + } - + public static async Task GetAllOrders(IRepository rep, int? customer, IMapper mapper) + { + var orders = await rep.GetAllOrders(customer); + + var response = mapper.Map>(orders); + + return TypedResults.Ok(response); + } + + public static async Task GetAllPizzas(IRepository rep, IMapper mapper) + { + var pizzas = await rep.GetAllPizzas(); + var response = mapper.Map>(pizzas); + + return TypedResults.Ok(response); + } + + public static async Task GetAllCustomers(IRepository rep, IMapper mapper) + { + var customers = await rep.GetAllCustomers(); + var response = mapper.Map>(customers); + + return TypedResults.Ok(response); + } + + } } diff --git a/exercise.pizzashopapi/Migrations/20250127085945_First.Designer.cs b/exercise.pizzashopapi/Migrations/20250127085945_First.Designer.cs new file mode 100644 index 0000000..7d2c3c9 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127085945_First.Designer.cs @@ -0,0 +1,115 @@ +// +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("20250127085945_First")] + partial class First + { + /// + 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("CustomerId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("CustomerId", "PizzaId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + }); + + 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/20250127085945_First.cs b/exercise.pizzashopapi/Migrations/20250127085945_First.cs new file mode 100644 index 0000000..5972260 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127085945_First.cs @@ -0,0 +1,84 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class First : 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: "Orders", + columns: table => new + { + CustomerId = table.Column(type: "integer", nullable: false), + PizzaId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Orders", x => new { x.CustomerId, x.PizzaId }); + table.ForeignKey( + name: "FK_Orders_customer_CustomerId", + column: x => x.CustomerId, + principalTable: "customer", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Orders_pizza_PizzaId", + column: x => x.PizzaId, + principalTable: "pizza", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Orders_PizzaId", + table: "Orders", + column: "PizzaId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Orders"); + + migrationBuilder.DropTable( + name: "customer"); + + migrationBuilder.DropTable( + name: "pizza"); + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250127095024_Second_seed.Designer.cs b/exercise.pizzashopapi/Migrations/20250127095024_Second_seed.Designer.cs new file mode 100644 index 0000000..ea09abd --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127095024_Second_seed.Designer.cs @@ -0,0 +1,153 @@ +// +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("20250127095024_Second_seed")] + partial class Second_seed + { + /// + 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"); + + b.HasData( + new + { + Id = 3, + Name = "Johhny" + }, + new + { + Id = 4, + Name = "Gunnar" + }); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("CustomerId", "PizzaId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + + b.HasData( + new + { + CustomerId = 3, + PizzaId = 4 + }, + new + { + CustomerId = 4, + PizzaId = 3 + }); + }); + + 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"); + + b.HasData( + new + { + Id = 3, + Name = "Pepperoni", + Price = 8.99m + }, + new + { + Id = 4, + Name = "BBQ chicken", + Price = 10.99m + }); + }); + + 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/20250127095024_Second_seed.cs b/exercise.pizzashopapi/Migrations/20250127095024_Second_seed.cs new file mode 100644 index 0000000..8de987f --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127095024_Second_seed.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class Second_seed : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250127095103_Third_seed.Designer.cs b/exercise.pizzashopapi/Migrations/20250127095103_Third_seed.Designer.cs new file mode 100644 index 0000000..a9d9c62 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127095103_Third_seed.Designer.cs @@ -0,0 +1,153 @@ +// +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("20250127095103_Third_seed")] + partial class Third_seed + { + /// + 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"); + + b.HasData( + new + { + Id = 3, + Name = "Johhny" + }, + new + { + Id = 4, + Name = "Gunnar" + }); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("CustomerId", "PizzaId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + + b.HasData( + new + { + CustomerId = 3, + PizzaId = 4 + }, + new + { + CustomerId = 4, + PizzaId = 3 + }); + }); + + 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"); + + b.HasData( + new + { + Id = 3, + Name = "Pepperoni", + Price = 8.99m + }, + new + { + Id = 4, + Name = "BBQ chicken", + Price = 10.99m + }); + }); + + 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/20250127095103_Third_seed.cs b/exercise.pizzashopapi/Migrations/20250127095103_Third_seed.cs new file mode 100644 index 0000000..cea7eff --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127095103_Third_seed.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class Third_seed : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250127095652_Fourth.Designer.cs b/exercise.pizzashopapi/Migrations/20250127095652_Fourth.Designer.cs new file mode 100644 index 0000000..ae7e8bc --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127095652_Fourth.Designer.cs @@ -0,0 +1,163 @@ +// +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("20250127095652_Fourth")] + partial class Fourth + { + /// + 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"); + + b.HasData( + new + { + Id = 3, + Name = "Johhny" + }, + new + { + Id = 4, + Name = "Gunnar" + }); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("CustomerId", "PizzaId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + + b.HasData( + new + { + CustomerId = 1, + PizzaId = 2 + }, + new + { + CustomerId = 2, + PizzaId = 1 + }, + new + { + CustomerId = 3, + PizzaId = 4 + }, + new + { + CustomerId = 4, + PizzaId = 3 + }); + }); + + 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"); + + b.HasData( + new + { + Id = 3, + Name = "Pepperoni", + Price = 8.99m + }, + new + { + Id = 4, + Name = "BBQ chicken", + Price = 10.99m + }); + }); + + 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/20250127095652_Fourth.cs b/exercise.pizzashopapi/Migrations/20250127095652_Fourth.cs new file mode 100644 index 0000000..07e3026 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127095652_Fourth.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class Fourth : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.InsertData( + table: "Orders", + columns: new[] { "CustomerId", "PizzaId" }, + values: new object[,] + { + { 1, 2 }, + { 2, 1 } + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "Orders", + keyColumns: new[] { "CustomerId", "PizzaId" }, + keyValues: new object[] { 1, 2 }); + + migrationBuilder.DeleteData( + table: "Orders", + keyColumns: new[] { "CustomerId", "PizzaId" }, + keyValues: new object[] { 2, 1 }); + } + } +} diff --git a/exercise.pizzashopapi/Migrations/20250127133921_Fifth.Designer.cs b/exercise.pizzashopapi/Migrations/20250127133921_Fifth.Designer.cs new file mode 100644 index 0000000..62cb811 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127133921_Fifth.Designer.cs @@ -0,0 +1,174 @@ +// +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("20250127133921_Fifth")] + partial class Fifth + { + /// + 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"); + + b.HasData( + new + { + Id = 3, + Name = "Johhny" + }, + new + { + Id = 4, + Name = "Gunnar" + }, + new + { + Id = 8, + Name = "Håkon" + }); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("CustomerId", "PizzaId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + + b.HasData( + new + { + CustomerId = 1, + PizzaId = 2 + }, + new + { + CustomerId = 2, + PizzaId = 1 + }, + new + { + CustomerId = 3, + PizzaId = 4 + }, + new + { + CustomerId = 4, + PizzaId = 3 + }); + }); + + 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"); + + b.HasData( + new + { + Id = 3, + Name = "Pepperoni", + Price = 8.99m + }, + new + { + Id = 4, + Name = "BBQ chicken", + Price = 10.99m + }, + new + { + Id = 9, + Name = "Meatlover", + Price = 12.99m + }); + }); + + 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/20250127133921_Fifth.cs b/exercise.pizzashopapi/Migrations/20250127133921_Fifth.cs new file mode 100644 index 0000000..ab218a1 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/20250127133921_Fifth.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace exercise.pizzashopapi.Migrations +{ + /// + public partial class Fifth : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.InsertData( + table: "customer", + columns: new[] { "id", "name" }, + values: new object[] { 8, "Håkon" }); + + migrationBuilder.InsertData( + table: "pizza", + columns: new[] { "id", "name", "price" }, + values: new object[] { 9, "Meatlover", 12.99m }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "customer", + keyColumn: "id", + keyValue: 8); + + migrationBuilder.DeleteData( + table: "pizza", + keyColumn: "id", + keyValue: 9); + } + } +} diff --git a/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs b/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs new file mode 100644 index 0000000..29b4270 --- /dev/null +++ b/exercise.pizzashopapi/Migrations/DataContextModelSnapshot.cs @@ -0,0 +1,171 @@ +// +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"); + + b.HasData( + new + { + Id = 3, + Name = "Johhny" + }, + new + { + Id = 4, + Name = "Gunnar" + }, + new + { + Id = 8, + Name = "Håkon" + }); + }); + + modelBuilder.Entity("exercise.pizzashopapi.Models.Order", b => + { + b.Property("CustomerId") + .HasColumnType("integer"); + + b.Property("PizzaId") + .HasColumnType("integer"); + + b.HasKey("CustomerId", "PizzaId"); + + b.HasIndex("PizzaId"); + + b.ToTable("Orders"); + + b.HasData( + new + { + CustomerId = 1, + PizzaId = 2 + }, + new + { + CustomerId = 2, + PizzaId = 1 + }, + new + { + CustomerId = 3, + PizzaId = 4 + }, + new + { + CustomerId = 4, + PizzaId = 3 + }); + }); + + 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"); + + b.HasData( + new + { + Id = 3, + Name = "Pepperoni", + Price = 8.99m + }, + new + { + Id = 4, + Name = "BBQ chicken", + Price = 10.99m + }, + new + { + Id = 9, + Name = "Meatlover", + Price = 12.99m + }); + }); + + 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/Customer.cs b/exercise.pizzashopapi/Models/Customer.cs index 2ca83bd..f003b7a 100644 --- a/exercise.pizzashopapi/Models/Customer.cs +++ b/exercise.pizzashopapi/Models/Customer.cs @@ -1,10 +1,18 @@ -using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace exercise.pizzashopapi.Models { + [Table("customer")] public class Customer { + [Key] + [Column("id")] public int Id { get; set; } + + [Column("name")] public string Name { get; set; } + + public IEnumerable Orders { get; set; } } } diff --git a/exercise.pizzashopapi/Models/Order.cs b/exercise.pizzashopapi/Models/Order.cs index fbe6113..3cbc3d6 100644 --- a/exercise.pizzashopapi/Models/Order.cs +++ b/exercise.pizzashopapi/Models/Order.cs @@ -4,7 +4,14 @@ namespace exercise.pizzashopapi.Models { public class Order { - + [ForeignKey("customer_id")] + public int CustomerId { get; set; } + + [ForeignKey("pizza_id")] + public int PizzaId { get; set; } + + public Customer Customer { get; set; } + public Pizza Pizza { get; set; } } } diff --git a/exercise.pizzashopapi/Models/Pizza.cs b/exercise.pizzashopapi/Models/Pizza.cs index 5c085ec..1fe591e 100644 --- a/exercise.pizzashopapi/Models/Pizza.cs +++ b/exercise.pizzashopapi/Models/Pizza.cs @@ -1,12 +1,21 @@ -using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace exercise.pizzashopapi.Models { - + [Table("pizza")] public class Pizza - { + { + [Key] + [Column("id")] public int Id { get; set; } + + [Column("name")] public string Name { get; set; } + + [Column("price")] public decimal Price { get; set; } + + public IEnumerable Orders { get; set; } } } \ No newline at end of file diff --git a/exercise.pizzashopapi/Program.cs b/exercise.pizzashopapi/Program.cs index c04a440..cddd882 100644 --- a/exercise.pizzashopapi/Program.cs +++ b/exercise.pizzashopapi/Program.cs @@ -8,6 +8,7 @@ builder.Services.AddControllers(); builder.Services.AddScoped(); +builder.Services.AddAutoMapper(typeof(Program)); 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 b114ea8..81304b7 100644 --- a/exercise.pizzashopapi/Repository/IRepository.cs +++ b/exercise.pizzashopapi/Repository/IRepository.cs @@ -5,7 +5,11 @@ namespace exercise.pizzashopapi.Repository public interface IRepository { Task> GetOrdersByCustomer(int id); - + Task> GetAllOrders(int? customerId); + + Task> GetAllPizzas(); + + Task> GetAllCustomers(); } } diff --git a/exercise.pizzashopapi/Repository/Repository.cs b/exercise.pizzashopapi/Repository/Repository.cs index e109fce..24e7746 100644 --- a/exercise.pizzashopapi/Repository/Repository.cs +++ b/exercise.pizzashopapi/Repository/Repository.cs @@ -1,11 +1,36 @@ using exercise.pizzashopapi.Data; using exercise.pizzashopapi.Models; +using Microsoft.EntityFrameworkCore; namespace exercise.pizzashopapi.Repository { public class Repository : IRepository { private DataContext _db; + public Repository(DataContext db) + { + _db = db; + } + + public async Task> GetAllCustomers() + { + return await _db.Customers.Include(c => c.Orders).ToListAsync(); + } + + public async Task> GetAllOrders(int? customerId) + { + if (customerId == null) return await _db.Orders.Include(c => c.Customer).Include(p => p.Pizza).ToListAsync(); + + return await _db.Orders.Where(o => o.CustomerId == customerId).Include(c => c.Customer).Include(p => p.Pizza).ToListAsync(); + + } + + public async Task> GetAllPizzas() + { + return await _db.Pizzas.Include(p => p.Orders).ToListAsync(); + } + + // Used optional customerId parameter in GetAllOrders instead public Task> GetOrdersByCustomer(int id) { throw new NotImplementedException(); diff --git a/exercise.pizzashopapi/Tools/MappingProfile.cs b/exercise.pizzashopapi/Tools/MappingProfile.cs new file mode 100644 index 0000000..1f41e58 --- /dev/null +++ b/exercise.pizzashopapi/Tools/MappingProfile.cs @@ -0,0 +1,18 @@ +using AutoMapper; +using exercise.pizzashopapi.DTOs; +using exercise.pizzashopapi.Models; + +namespace exercise.pizzashopapi.Tools +{ + public class MappingProfile : Profile + { + public MappingProfile() + { + CreateMap(); + CreateMap(); + CreateMap() + .ForMember(x => x.CustomerName, opt => opt.MapFrom(y => y.Customer.Name)) + .ForMember(z => z.PizzaName, opt => opt.MapFrom(p => p.Pizza.Name)); + } + } +} diff --git a/exercise.pizzashopapi/exercise.pizzashopapi.csproj b/exercise.pizzashopapi/exercise.pizzashopapi.csproj index 624203b..4a3bdd5 100644 --- a/exercise.pizzashopapi/exercise.pizzashopapi.csproj +++ b/exercise.pizzashopapi/exercise.pizzashopapi.csproj @@ -11,6 +11,7 @@ + all