diff --git a/.gitignore b/.gitignore index d5dca0c..d36338e 100644 --- a/.gitignore +++ b/.gitignore @@ -412,3 +412,5 @@ FodyWeavers.xsd # Built Visual Studio Code Extensions *.vsix +/WebAPIWithEF/ContosoPizza.db-shm +/WebAPIWithEF/ContosoPizza.db-wal diff --git a/WebAPIWithEF/ContosoPizza.db b/WebAPIWithEF/ContosoPizza.db new file mode 100644 index 0000000..de02397 Binary files /dev/null and b/WebAPIWithEF/ContosoPizza.db differ diff --git a/WebAPIWithEF/Controllers/PizzaController.cs b/WebAPIWithEF/Controllers/PizzaController.cs new file mode 100644 index 0000000..68fe28c --- /dev/null +++ b/WebAPIWithEF/Controllers/PizzaController.cs @@ -0,0 +1,77 @@ +using Microsoft.AspNetCore.Mvc; +using WebAPIWithEF.Models; +using WebAPIWithEF.Services; + +namespace WebAPIWithEF.Controllers +{ + [ApiController] + [Route("controller")] + public class PizzaController : ControllerBase + { + PizzaService _service; + + public PizzaController(PizzaService service) + { + _service = service; + } + + [HttpGet] + public IEnumerable GetAll() + { + return _service.GetAll(); + } + + [HttpGet("{id}")] + public ActionResult GetById(int id) + { + var pizza = _service.GetById(id); + if (pizza is null) + return NotFound(); + + return pizza; + } + + [HttpPost] + public IActionResult Create(Pizza newPizza) + { + var pizza = _service.Create(newPizza); + return CreatedAtAction(nameof(GetById), new { id = pizza!.Id }, pizza); + } + + [HttpPut("{id}/addtopping")] + public IActionResult AddTopping(int id, int toppingId) + { + var pizzaToUpdate = _service.GetById(id); + if (pizzaToUpdate is null) + return NotFound(); + + _service.AddTopping(id, toppingId); + + return NoContent(); + } + + [HttpPut("{id}/updatesauce")] + public IActionResult UpdateSauce(int id, int sauceId) + { + var pizzaToUpdate = _service.GetById(id); + if (pizzaToUpdate is null) + return NotFound(); + + _service.UpdateSauce(id, sauceId); + + return NoContent(); + } + + [HttpDelete("{id}")] + public IActionResult Delete(int id) + { + var pizza = _service.GetById(id); + if (pizza is null) + return NotFound(); + + _service.DeleteById(id); + + return Ok(); + } + } +} diff --git a/WebAPIWithEF/Controllers/WeatherForecastController.cs b/WebAPIWithEF/Controllers/WeatherForecastController.cs deleted file mode 100644 index 4b0e080..0000000 --- a/WebAPIWithEF/Controllers/WeatherForecastController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace WebAPIWithEF.Controllers -{ - [ApiController] - [Route("[controller]")] - public class WeatherForecastController : ControllerBase - { - private static readonly string[] Summaries = new[] - { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - }; - - private readonly ILogger _logger; - - public WeatherForecastController(ILogger logger) - { - _logger = logger; - } - - [HttpGet(Name = "GetWeatherForecast")] - public IEnumerable Get() - { - return Enumerable.Range(1, 5).Select(index => new WeatherForecast - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = Summaries[Random.Shared.Next(Summaries.Length)] - }) - .ToArray(); - } - } -} diff --git a/WebAPIWithEF/Data/PizzaContext.cs b/WebAPIWithEF/Data/PizzaContext.cs new file mode 100644 index 0000000..84a49cc --- /dev/null +++ b/WebAPIWithEF/Data/PizzaContext.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore; +using WebAPIWithEF.Models; + +namespace WebAPIWithEF.Data +{ + public class PizzaContext : DbContext + { + public DbSet Pizzas => Set(); + public DbSet Toppings => Set(); + public DbSet Sauces => Set(); + + public PizzaContext(DbContextOptions options) : base(options) + { + + } + } +} diff --git a/WebAPIWithEF/Migrations/20240611075625_InitialCreate.Designer.cs b/WebAPIWithEF/Migrations/20240611075625_InitialCreate.Designer.cs new file mode 100644 index 0000000..a80b964 --- /dev/null +++ b/WebAPIWithEF/Migrations/20240611075625_InitialCreate.Designer.cs @@ -0,0 +1,98 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using WebAPIWithEF.Data; + +#nullable disable + +namespace WebAPIWithEF.Migrations +{ + [DbContext(typeof(PizzaContext))] + [Migration("20240611075625_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.6"); + + modelBuilder.Entity("WebAPIWithEF.Models.Pizza", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("SauceId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SauceId"); + + b.ToTable("Pizzas"); + }); + + modelBuilder.Entity("WebAPIWithEF.Models.Sauce", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Sauces"); + }); + + modelBuilder.Entity("WebAPIWithEF.Models.Topping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("PizzaId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PizzaId"); + + b.ToTable("Toppings"); + }); + + modelBuilder.Entity("WebAPIWithEF.Models.Pizza", b => + { + b.HasOne("WebAPIWithEF.Models.Sauce", "Sauce") + .WithMany() + .HasForeignKey("SauceId"); + + b.Navigation("Sauce"); + }); + + modelBuilder.Entity("WebAPIWithEF.Models.Topping", b => + { + b.HasOne("WebAPIWithEF.Models.Pizza", null) + .WithMany("Toppings") + .HasForeignKey("PizzaId"); + }); + + modelBuilder.Entity("WebAPIWithEF.Models.Pizza", b => + { + b.Navigation("Toppings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WebAPIWithEF/Migrations/20240611075625_InitialCreate.cs b/WebAPIWithEF/Migrations/20240611075625_InitialCreate.cs new file mode 100644 index 0000000..88268e7 --- /dev/null +++ b/WebAPIWithEF/Migrations/20240611075625_InitialCreate.cs @@ -0,0 +1,88 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace WebAPIWithEF.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Sauces", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Sauces", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Pizzas", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", nullable: true), + SauceId = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Pizzas", x => x.Id); + table.ForeignKey( + name: "FK_Pizzas_Sauces_SauceId", + column: x => x.SauceId, + principalTable: "Sauces", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "Toppings", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", nullable: true), + PizzaId = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Toppings", x => x.Id); + table.ForeignKey( + name: "FK_Toppings_Pizzas_PizzaId", + column: x => x.PizzaId, + principalTable: "Pizzas", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_Pizzas_SauceId", + table: "Pizzas", + column: "SauceId"); + + migrationBuilder.CreateIndex( + name: "IX_Toppings_PizzaId", + table: "Toppings", + column: "PizzaId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Toppings"); + + migrationBuilder.DropTable( + name: "Pizzas"); + + migrationBuilder.DropTable( + name: "Sauces"); + } + } +} diff --git a/WebAPIWithEF/Migrations/PizzaContextModelSnapshot.cs b/WebAPIWithEF/Migrations/PizzaContextModelSnapshot.cs new file mode 100644 index 0000000..abc4b7a --- /dev/null +++ b/WebAPIWithEF/Migrations/PizzaContextModelSnapshot.cs @@ -0,0 +1,95 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using WebAPIWithEF.Data; + +#nullable disable + +namespace WebAPIWithEF.Migrations +{ + [DbContext(typeof(PizzaContext))] + partial class PizzaContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.6"); + + modelBuilder.Entity("WebAPIWithEF.Models.Pizza", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("SauceId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SauceId"); + + b.ToTable("Pizzas"); + }); + + modelBuilder.Entity("WebAPIWithEF.Models.Sauce", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Sauces"); + }); + + modelBuilder.Entity("WebAPIWithEF.Models.Topping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("PizzaId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PizzaId"); + + b.ToTable("Toppings"); + }); + + modelBuilder.Entity("WebAPIWithEF.Models.Pizza", b => + { + b.HasOne("WebAPIWithEF.Models.Sauce", "Sauce") + .WithMany() + .HasForeignKey("SauceId"); + + b.Navigation("Sauce"); + }); + + modelBuilder.Entity("WebAPIWithEF.Models.Topping", b => + { + b.HasOne("WebAPIWithEF.Models.Pizza", null) + .WithMany("Toppings") + .HasForeignKey("PizzaId"); + }); + + modelBuilder.Entity("WebAPIWithEF.Models.Pizza", b => + { + b.Navigation("Toppings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WebAPIWithEF/Models/Pizza.cs b/WebAPIWithEF/Models/Pizza.cs new file mode 100644 index 0000000..7215897 --- /dev/null +++ b/WebAPIWithEF/Models/Pizza.cs @@ -0,0 +1,10 @@ +namespace WebAPIWithEF.Models +{ + public class Pizza + { + public int Id { get; set; } + public string? Name { get; set; } + public Sauce? Sauce { get; set; } + public ICollection? Toppings { get; set; } + } +} diff --git a/WebAPIWithEF/Models/Sauce.cs b/WebAPIWithEF/Models/Sauce.cs new file mode 100644 index 0000000..b3cf2d1 --- /dev/null +++ b/WebAPIWithEF/Models/Sauce.cs @@ -0,0 +1,8 @@ +namespace WebAPIWithEF.Models +{ + public class Sauce + { + public int Id { get; set; } + public string? Name { get; set; } + } +} diff --git a/WebAPIWithEF/Models/Topping.cs b/WebAPIWithEF/Models/Topping.cs new file mode 100644 index 0000000..e4c9747 --- /dev/null +++ b/WebAPIWithEF/Models/Topping.cs @@ -0,0 +1,8 @@ +namespace WebAPIWithEF.Models +{ + public class Topping + { + public int Id { get; set; } + public string? Name { get; set; } + } +} diff --git a/WebAPIWithEF/Program.cs b/WebAPIWithEF/Program.cs index ec3e32d..ec6dcc3 100644 --- a/WebAPIWithEF/Program.cs +++ b/WebAPIWithEF/Program.cs @@ -1,4 +1,7 @@ +using WebAPIWithEF.Data; +using WebAPIWithEF.Services; + namespace WebAPIWithEF { public class Program @@ -14,6 +17,10 @@ namespace WebAPIWithEF builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); + builder.Services.AddSqlite("Data Source=ContosoPizza.db"); + + builder.Services.AddScoped(); + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -30,6 +37,8 @@ namespace WebAPIWithEF app.MapControllers(); + app.MapGet("/", () => @"Contoso Pizza management API. Navigate to /swagger to open the Swagger test UI."); + app.Run(); } } diff --git a/WebAPIWithEF/Services/PizzaService.cs b/WebAPIWithEF/Services/PizzaService.cs new file mode 100644 index 0000000..cbb3e22 --- /dev/null +++ b/WebAPIWithEF/Services/PizzaService.cs @@ -0,0 +1,37 @@ +using WebAPIWithEF.Models; + +namespace WebAPIWithEF.Services +{ + public class PizzaService + { + public IEnumerable GetAll() + { + throw new NotImplementedException(); + } + + public Pizza? GetById(int id) + { + throw new NotImplementedException(); + } + + public Pizza? Create(Pizza newPizza) + { + throw new NotImplementedException(); + } + + public void AddTopping(int PizzaId, int ToppingId) + { + throw new NotImplementedException(); + } + + public void UpdateSauce(int PizzaId, int SauceId) + { + throw new NotImplementedException(); + } + + public void DeleteById(int id) + { + throw new NotImplementedException(); + } + } +} diff --git a/WebAPIWithEF/Views/Pizza/Create.cshtml b/WebAPIWithEF/Views/Pizza/Create.cshtml new file mode 100644 index 0000000..bb23ff9 --- /dev/null +++ b/WebAPIWithEF/Views/Pizza/Create.cshtml @@ -0,0 +1,33 @@ +@model WebAPIWithEF.Models.Pizza + +@{ + ViewData["Title"] = "Create"; +} + +

Create

+ +

Pizza

+
+
+
+
+
+
+ + + +
+
+ +
+
+
+
+ + + +@section Scripts { + @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} +} diff --git a/WebAPIWithEF/Views/Pizza/Delete.cshtml b/WebAPIWithEF/Views/Pizza/Delete.cshtml new file mode 100644 index 0000000..660073c --- /dev/null +++ b/WebAPIWithEF/Views/Pizza/Delete.cshtml @@ -0,0 +1,27 @@ +@model WebAPIWithEF.Models.Pizza + +@{ + ViewData["Title"] = "Delete"; +} + +

Delete

+ +

Are you sure you want to delete this?

+
+

Pizza

+
+
+
+ @Html.DisplayNameFor(model => model.Name) +
+
+ @Html.DisplayFor(model => model.Name) +
+
+ +
+ + | + Back to List +
+
diff --git a/WebAPIWithEF/Views/Pizza/Details.cshtml b/WebAPIWithEF/Views/Pizza/Details.cshtml new file mode 100644 index 0000000..bf903d1 --- /dev/null +++ b/WebAPIWithEF/Views/Pizza/Details.cshtml @@ -0,0 +1,24 @@ +@model WebAPIWithEF.Models.Pizza + +@{ + ViewData["Title"] = "Details"; +} + +

Details

+ +
+

Pizza

+
+
+
+ @Html.DisplayNameFor(model => model.Name) +
+
+ @Html.DisplayFor(model => model.Name) +
+
+
+ diff --git a/WebAPIWithEF/Views/Pizza/Edit.cshtml b/WebAPIWithEF/Views/Pizza/Edit.cshtml new file mode 100644 index 0000000..3292063 --- /dev/null +++ b/WebAPIWithEF/Views/Pizza/Edit.cshtml @@ -0,0 +1,34 @@ +@model WebAPIWithEF.Models.Pizza + +@{ + ViewData["Title"] = "Edit"; +} + +

Edit

+ +

Pizza

+
+
+
+
+
+ +
+ + + +
+
+ +
+
+
+
+ + + +@section Scripts { + @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} +} diff --git a/WebAPIWithEF/Views/Pizza/Index.cshtml b/WebAPIWithEF/Views/Pizza/Index.cshtml new file mode 100644 index 0000000..8a5c054 --- /dev/null +++ b/WebAPIWithEF/Views/Pizza/Index.cshtml @@ -0,0 +1,35 @@ +@model IEnumerable + +@{ + ViewData["Title"] = "Index"; +} + +

Index

+ +

+ Create New +

+ + + + + + + + +@foreach (var item in Model) { + + + + +} + +
+ @Html.DisplayNameFor(model => model.Name) +
+ @Html.DisplayFor(modelItem => item.Name) + + Edit | + Details | + Delete +
diff --git a/WebAPIWithEF/Views/Shared/_ValidationScriptsPartial.cshtml b/WebAPIWithEF/Views/Shared/_ValidationScriptsPartial.cshtml new file mode 100644 index 0000000..ed86611 --- /dev/null +++ b/WebAPIWithEF/Views/Shared/_ValidationScriptsPartial.cshtml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/WebAPIWithEF/WebAPIWithEF.csproj b/WebAPIWithEF/WebAPIWithEF.csproj index c6ec4d4..bafda6e 100644 --- a/WebAPIWithEF/WebAPIWithEF.csproj +++ b/WebAPIWithEF/WebAPIWithEF.csproj @@ -12,6 +12,11 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/WebAPIWithEF/WebAPIWithEF.sln b/WebAPIWithEF/WebAPIWithEF.sln new file mode 100644 index 0000000..9d2652e --- /dev/null +++ b/WebAPIWithEF/WebAPIWithEF.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebAPIWithEF", "WebAPIWithEF.csproj", "{15DD3482-AF95-48A4-B767-68065D7905CE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {15DD3482-AF95-48A4-B767-68065D7905CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15DD3482-AF95-48A4-B767-68065D7905CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15DD3482-AF95-48A4-B767-68065D7905CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15DD3482-AF95-48A4-B767-68065D7905CE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5918194D-EDF5-46B7-8BC7-0DD12D6E98AF} + EndGlobalSection +EndGlobal