Enoncé TP2 ASP - Net EntityFramework [PDF]

  • 0 0 0
  • Gefällt Ihnen dieses papier und der download? Sie können Ihre eigene PDF-Datei in wenigen Minuten kostenlos online veröffentlichen! Anmelden
Datei wird geladen, bitte warten...
Zitiervorschau

Module au choix : Programmation .NET/C#

2ATEL

A.U. 2020/2021

TP : EF core avec des projets séparés Part 1 – Mise en place de la solution: 1. Créer une solution nommé “MyFinance” et y ajouter 3projets : - MyFinance.BL (Class Library) : correspond à la couche métier où vous placer les objets métier correspondant à tous les objets spécifiques que vous allez manipuler - MyFinance.DAL (Class Library) : correspond à la couche accès aux données (DbContext and Migrations) - MyFinance.Web (ASP.NET Core Web Application — MVC)

2. Ajouter les dépendances nécessaires pour chaque projet - Le projet DAL fait référence au projet BL

-

Le projet Web fait référence aux projets BL et DAL

Page 1 sur 9

Module au choix : Programmation .NET/C#

2ATEL

A.U. 2020/2021

Part 2 – Le projet BL (Business Layer): Etape 1 : -

Ajouter les classes schématisées dans le diagramme (Classes déjà implémentées)

Part 3 – Le projet DAL (Data Access Layer): 1. Ajouter les Packages NuGet avec le gestionnaire de packages NuGet - « Microsoft.EntityFrameworkCore.SqlServer » et - « Microsoft.EntityFrameworkCore.Tools » (pour la génération de fichier de migrations)

Page 2 sur 9

Module au choix : Programmation .NET/C#

2ATEL

A.U. 2020/2021

NB : - Il faut choisir la bonne version à installer - Ie projet DAL doit être le projet de démarrage

2. Définir le DbContext - Ajouter la classe ApplicationDbContext public class ApplicationDbContext: DbContext { public public public public public

DbSet Category { get; set; } DbSet Product { get; set; } DbSet Provider { get; set; } DbSet Biological { get; set; } DbSet Chemical { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(@"Data Source=(localdb)\MSSQLLocalDB;Initial Security=True;"); }

Catalog=MyFinanceDB; Integrated

protected override void OnModelCreating(ModelBuilder modelBuilder) { // One to Many modelBuilder.Entity() .HasMany(c => c.Products) .WithOne(e => e.Category) .OnDelete(DeleteBehavior.Cascade); // Many to many modelBuilder.Entity() .HasKey(bc => new { bc.ProductId, bc.ProviderId }); modelBuilder.Entity() .HasOne(bc => bc.Product) .WithMany(b => b.ProductProviders) .HasForeignKey(bc => bc.ProductId); modelBuilder.Entity() .HasOne(bc => bc.Provider) .WithMany(c => c.ProductProviders) .HasForeignKey(bc => bc.ProviderId); } }

Page 3 sur 9

Module au choix : Programmation .NET/C#

-

2ATEL

A.U. 2020/2021

Créer la base de données : NuGet Package Manager Console → Update-Database

Partie 4 – Le Projet Web 1. Seeding la base de données: -

Ajouter La chaine de connexion sql dans appsettings.json du projet MyFinane.Web

"ConnectionStrings": { "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyFinanceDB;Trusted_Connection=True; MultipleActiveResultSets=true" }

-

Modifier la classe MyFinanceDbContext

public MyFinanceDbContext(DbContextOptions options) : base(options) { } /* {

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

optionsBuilder.UseSqlServer(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=MyFinanceDB; Integrated Security=True;"); }*/

-

Dans « Startup.cs ». Enregistrer le dbContext dans les services en ajout le code suivant :

public void ConfigureServices(IServiceCollection services) { services.AddDbContext(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }

Page 4 sur 9

Module au choix : Programmation .NET/C#

2ATEL

A.U. 2020/2021

2. Ajouter une classe qui implémente l’interface IDesignTimeDbContextFactory. Cette fabrique va être utilisée par les outils EF pour créer une instance de votre DBContext. Le code de ce fichier est le suivant : using using using using using

MyFinance.DAL; Microsoft.EntityFrameworkCore.Design; Microsoft.EntityFrameworkCore; Microsoft.Extensions.Configuration; System.IO;

namespace MyFinance.Web { public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory { public MyFinanceDbContext CreateDbContext(string[] args) { IConfigurationRoot configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile(@Directory.GetCurrentDirectory() + "/../MyFinance.Web/appsettings.json") .Build(); var builder = new DbContextOptionsBuilder(); var connectionString = configuration.GetConnectionString("DefaultConnection"); builder.UseSqlServer(connectionString); return new MyFinanceDbContext(builder.Options); } } }

-

Ajouter la classe

public class SeedData { public static void Initialize(MyFinanceDbContext context) { if (!context.Category.Any()) { var cats = new List() { new Category { Name = "Alimentaire" }, new Category { Name = "Cosmétique" }, new Category { Name = "Informatique" }, }; context.Category.AddRange(cats); context.SaveChanges(); } } }

-

Modifier la méthode Main du Program.cs

public static void Main(string[] args) { var host = CreateWebHostBuilder(args).Build(); using (var scope = host.Services.CreateScope()) { var services = scope.ServiceProvider; try { var context = services.GetRequiredService(); SeedData.Initialize(context); } catch (Exception) { Console.WriteLine("An error occurred while seeding the database."); } } host.Run(); }

Page 5 sur 9

Module au choix : Programmation .NET/C#

-

2ATEL

A.U. 2020/2021

Exécuter l’application MyFinance.Web Actualiser la base de données

3. Les images -

Modifier la classe ¨Product en ajoutant l’annotation suivante :

[DataType(DataType.ImageUrl)] [Display(Name = "Image")] public string ImageName { get; set; }

-

Dans Views/Products/Index.cshtml, ajoutez le code suivant :

@if (item.ImageName != null) {

}

Partie 5 : Personnaliser les pages de « Product » Quand une entité Produit est créée, elle doit avoir une relation avec une catégorie existant. Pour faciliter cela, le code du modèle généré automatiquement inclut des méthodes de contrôleur, et des vues Create et Edit qui incluent une liste déroulante pour sélectionner la catégorie. La liste déroulante définit la propriété de clé étrangère Product.CategoryId, qui est tout ce dont Entity Framework a besoin pour charger la propriété de navigation Category avec l’entité Category appropriée. Vous utilisez le code du modèle généré automatiquement, mais que vous modifiez un peu pour ajouter la gestion des erreurs et trier la liste déroulante. 1. Ajouter un contrôleur :

2. Dans ProductsController.cs, supprimez les quatre méthodes Create et Edit, et remplacez-les par le code suivant : Page 6 sur 9

Module au choix : Programmation .NET/C#

2ATEL

A.U. 2020/2021

public IActionResult Create() { CategorysDropDownList(); return View(); } [HttpPost] [ValidateAntiForgeryToken] public async Task Create([Bind("ProductID,Description,Name, Price, Quantity, ImageName, CategoryD")] Product product) { if (ModelState.IsValid) { _context.Add(product); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } CategorysDropDownList(product.CategoryId); return View(product); }

public async Task Edit(int? id) { if (id == null) { return NotFound(); } var product = await _context.Product .AsNoTracking() .FirstOrDefaultAsync(m => m.ProductId == id); if (product == null) { return NotFound(); } CategorysDropDownList(product.CategoryId); return View(product); } [HttpPost] [ValidateAntiForgeryToken] public async Task EditPost(int? id) { if (id == null) { return NotFound(); } var productToUpdate = await _context.Product .FirstOrDefaultAsync(c => c.ProductId == id); if (await TryUpdateModelAsync(productToUpdate, "", c => c.Name, c => c.Description, c => c.Price, c => c.Quantity, c => c.CategoryId, c => c.ImageName, c => c.DateProd)) { try { await _context.SaveChangesAsync(); } catch (DbUpdateException /* ex */) { //Log the error (uncomment ex variable name and write a log.) ModelState.AddModelError("", "Unable to save changes. " + "Try again, and if the problem persists, " + "see your system administrator."); } return RedirectToAction(nameof(Index)); } CategorysDropDownList(productToUpdate.CategoryId); return View(productToUpdate); }

Page 7 sur 9

Module au choix : Programmation .NET/C#

2ATEL

A.U. 2020/2021

Après la méthode HttpPost Edit, créez une méthode qui charge les informations des catégories pour la liste déroulante. private void CategorysDropDownList(object selectedCategory = null) { var categorysQuery = from d in _context.Category orderby d.Name select d; ViewBag.CategoryId = new SelectList(categorysQuery.AsNoTracking(), "CategoryId", "Name", selectedCategory); }

La méthode CategorysDropDownList obtient une liste de toutes les catégories triées par nom, crée une collection SelectList pour une liste déroulante et passe la collection à la vue dans ViewBag. La méthode accepte le paramètre facultatif selectedCategory qui permet au code appelant de spécifier l’élément sélectionné lors de l’affichage de la liste déroulante. La vue passe le nom « CategoryId » pour le tag helper : le helper peut alors rechercher dans l’objet ViewBag une SelectList nommée « CategoryId ». La méthode HttpGet Create appelle la méthode CategorysDropDownList sans définir l’élément sélectionné, car pour un nouveau cours, le département n’est pas encore établi. La méthode HttpGet Edit définit l’élément sélectionné, en fonction de l’ID de la catégorie qui est déjà affectée au Produit à modifier Les méthodes HttpPost pour Create et pour Edit incluent également du code qui définit l’élément sélectionné quand elles réaffichent la page après une erreur. Ceci garantit que quand la page est réaffichée pour montrer le message d’erreur, la catégorie qui a été sélectionnée le reste. 3. Ajouter .AsNoTracking aux méthodes Details et Delete Pour optimiser les performances des pages Details et Delete pour les produits, ajoutez des appels de AsNoTracking dans les méthodes Details et HttpGet Delete. public async Task Delete(int? id) { if (id == null) { return NotFound(); } var product = await _context.Product .Include(p => p.Category) .AsNoTracking() .FirstOrDefaultAsync(m => m.ProductId == id); if (product == null) { return NotFound(); } return View(product); } public async Task Details(int? id) { if (id == null) { return NotFound(); } var product = await _context.Product .Include(p => p.Category) .AsNoTracking() .FirstOrDefaultAsync(m => m.ProductId == id);

Page 8 sur 9

Module au choix : Programmation .NET/C#

2ATEL

A.U. 2020/2021

if (product == null) { return NotFound(); } return View(product); }

4. Modifier les vues des cours Dans Views/Products/Create.cshtml, ajoutez une option « Select Category » à la liste déroulante Category, changez la légende de CategoryId en Category et ajoutez un message de validation.

-- Select Category --



Dans Views/Products/Edit.cshtml, faites les mêmes modifications pour le champ Category que ce que vous venez de faire dans Create.cshtml. Également dans Views/Products/Edit.cshtml, ajoutez un champ de numéro de produit avant le champ Name. Comme le numéro de produit est la clé primaire, il est affiché mais ne peut pas être modifié.

@Html.DisplayFor(model => model.ProductId)

Il existe déjà un champ masqué () pour le numéro de produit dans la vue Edit. L’ajout d’un tag helper n’élimine la nécessité d’avoir le champ masqué, car cela n’a pas comme effet que le numéro du produit est inclut dans les données envoyées quand l’utilisateur clique sur Save dans la page Edit. Dans Views/Products/Delete.cshtml, ajoutez un champ pour le numéro de produit en haut et changez l’ID de category en nom de Category.

@Html.DisplayNameFor(model => model.ProductId)

@Html.DisplayFor(model => model.ProductId)

@Html.DisplayNameFor(model => model.Category)

@Html.DisplayFor(model => model.Category.Name)

Dans Views/Products/Details.cshtml, faites la même modification que celle que vous venez de faire pour Delete.cshtml. 5. Testez les pages des produits

Page 9 sur 9