# Projet d'Entity FrameWork et Consomation et Développement de services Notre projet à pour objectif la liaison entre une base de donnée et un client, par l'utilisation d' ``EntityFramework`` et d'une ``API`` C#. ![C#](https://img.shields.io/badge/c%23-%23239120.svg?style=for-the-badge&logo=c-sharp&logoColor=white) ![JWT](https://img.shields.io/badge/JWT-black?style=for-the-badge&logo=JSON%20web%20tokens) ![Markdown](https://img.shields.io/badge/markdown-%23000000.svg?style=for-the-badge&logo=markdown&logoColor=white) > *A noter que seul la v1 est prise en compte, la v2 et v2.2 ne sont presentes uniquement pour prouver notre capacité à versionner* ### Ce projet est decoupé en deux parties : # :alien: Consomation et Développement de services ### :checkered_flag: État des livrables : > * :heavy_check_mark: Mise en place de toutes les opérations CRUD > * :heavy_check_mark: API RESTful (respect des règles de routage, utilisation des bons status code ...) > * :heavy_check_mark: Utilisation des fichiers configurations > * :heavy_check_mark: Versionnage de l'api (avec versionnage de la doc) > * :heavy_check_mark: Logs > * :heavy_check_mark: Tests unitaires > * :heavy_exclamation_mark: Réalisation du client MAUI et liaison avec l'api > * :heavy_check_mark:Liaison avec la base de données > * :heavy_check_mark:Filtrage + Pagination des données > * :heavy_check_mark Propreté du code (Vous pouvez vous servir de sonarqube) > * :heavy_check_mark: Dockerisation et Hébergement des API (CodeFirst) > * :heavy_exclamation_mark: Sécurité > * :heavy_check_mark: Utilisation SonarQube [![Build Status](https://codefirst.iut.uca.fr/api/badges/corentin.richard/EntityFramework_ConsoDeServices_TP/status.svg)](https://codefirst.iut.uca.fr/corentin.richard/EntityFramework_ConsoDeServices_TP) --- # :package: Entity FrameWork ### :checkered_flag: État des livrables : Partie 1 : * Exo1 : :heavy_check_mark: une base de données une table de champion utilisation du client console/mobile requetes CRUD (+ tri, filtrage) * Exo2 : :heavy_check_mark: UT Base de données stubbée SQLiteInMemory * Exo3 : :heavy_check_mark: Déploiement EF et tests via code#0 --- Partie 2 : * Exo4 : :heavy_check_mark: implémentation des runes et skins (1 table -> pas de relation) * Exo5 : :heavy_check_mark: Relation entre champion et skin (OneToMany) * Exo6 : :heavy_check_mark: Relation entre Champion, RunePage et Rune (ManyToMany) > La relation entre Rune et RunePage à été simplifiée par manque de temps, il ne s'agit donc pas d'un dictionaire mais d'un OneToMany. * Exo7 : :heavy_check_mark: mapping entre model et entité (intégration de qualité) (en 1 table et avec relations) * Exo8 : :heavy_exclamation_mark: Ajouter le paterne UnitOfWork (rollback en cas de probleme sur les transaction) --- ### Diagramme d'architechture : ![](./docAsset/Diagramme%20d'architecture.jpg) Le schéma ci-dessus décris l'architecture finale que doit avoir le projet, # Implémentation attendue : Tout en haut du schéma, la partie client est composé du client MAUI et et du client Console, ceux-ci permettent l'affichage des ressources, l'utilisation de l'architecture et donc de tester si tout le projet fonctionne. Celui-ci utilise le HTTPDataManager qui lui permet d'effectuer les requêtes à l'API afin de récupérer les données. Il hérite de IDataManager et peux donc être remplacé par EFDataManager, court-circuitant ainsi l'API ou par StubLib, n'utilisant pas l'API et l'EF. Le DataManager utilise l'une des extensions mapper pour convertir les objets DTO en Model. > On indique aux client d'utiliser le HttpDataManager : builder.Services.AddScoped(); En second, la partie API, celle-ci s'occupe de recevoir les requêtes et de renvoyer les objet en conséquent. Dans l'implémentation idéale, l'API utilise l'EFDataManger pour faire appel aux données stockés en base de données. Il hérite lui aussi de IDataManager mais ne peut être remplacé que par le StubLib.Il utilise lui aussi des extensions mapper pour convertir les objets Entity en Model. > On indique à l'API d'utiliser le EFDataManager : builder.Services.AddScoped(); Enfin, le dernier service implémenté est EntityFramework, l'ORM utilisé pour communiquer avec la base de données, celle-ci elle-même basé sur les données du StubLib grâce à la méthode HasData dans notre DbContext, il récupère et enregistre les objets Entity grâce aux DBSet d'objets. La fluent API permet de définir précisement les attributs de la base de données # Implémentation Réelle Actuellement, l'entiereté du projet est relié ensemble, cependant les fonctionnalités n'ont été implémentés que partielement, suite à un manque de temps nous avons préféré effectuer le squelette du projet et de relier l'ensemble plutôt que de rajouter des méthodes qui ne seraient pas utilisées. ## 1 - **Clients** Premièrement, les clients, ils dépendent de l'implémentation de HTTPDataManager : Le client MAUI : Suite à des difficultées de compatibilité et par manque de temps nous n'avons pas pu l'implémenter après plusieurs essais, le client console le remplace donc. Le client console est fonctionnel mais ne peut effectuer que peu de méthodes dans sont menu textuel : - Compter les champions - Afficher les champions - Afficher les skills d'un champion ## 2 - **API** L'**HTTPDataManger** permet d'appeler les méthodes basiques de la partie Champion de l'API. L'**API** ne présente qu'un seul controlleur, celui de champion. Nous avons préféré faire un seul complet plutôt que plusieurs incomplets. Celui-ci a l'utilisation des **logs**, des **codes de retours** et respecte les **règles Rest**, celui-ci implémentant les méthodes **CRUD**. Une seconde **version** est disponible pour implémenter un versionning. La méthode GET permet le **filtrage et la pagination** des données, ces méthodes sont **testées unitairement** et l'API est **déployé** avec le projet en conteneur. ## 3 - **EntityFramework** L'**EFDataManger** permet d'effectuer les méthodes CRUD sur EntityFramework. L'**EntityFramework** a été implémenté avec toutes les classes **Entity** dérivant du modèle, en utilisant **OneToMany** et **ManyToMany** de facon dérivé de celle prévue. Elle est utilsé sur **base** du stub et est **testé** unitairement grâce à **SQLiteInMemory**. Ces méthodes **CRUD** sont implémentées grâce à l'utilisation de l'**EFDataManager**, le *Mapper* entre entity et model est alors requis. Enfin il est **deployé**, cependant nous n'avons pas eu le temps d'aborder le pattern ***UnitOfWork***. # :rocket: Comment lancer le projet ## 1 - Cloner le dépot Premièrement il faut cloner le depot git à l'addresse suivant : git clone https://codefirst.iut.uca.fr/git/corentin.richard/EntityFramework_ConsoDeServices_TP.git ## 2 - Ouvir le projet avec VisualStudio clique droit sur le dossier cloné > ouvrir avec Visual Studio ## 3 - Configurer le démarrage du projet > clique droit sur le projet dans l'explorateur de solution > Configure Startup Projects ... > Multpile Startup Project Et mettez l'action Start à LoLAPI et à ConsoleApplication(c#) ou LoLApp(MAUI) ## 4 - Lancement du projet Vous pouvez alors lancer le projet grâce à la flèche verte, bonne navigation ! # Développeurs : ``Corentin Richard`` : **[corentin.richard@etu.uca.fr](https://codefirst.iut.uca.fr/git/corentin.richard)** ``Pierre Ferreira`` : **[pierre.ferreira@etu.uca.fr](https://codefirst.iut.uca.fr/git/pierre.ferreira)** # Diagrammes du Model Initial ## Diagramme de classes du modèle ```mermaid classDiagram class LargeImage{ +/Base64 : string } class Champion{ +/Name : string +/Bio : string +/Icon : string +/Characteristics : Dictionary~string, int~ ~ AddSkin(skin : Skin) bool ~ RemoveSkin(skin: Skin) bool + AddSkill(skill: Skill) bool + RemoveSkill(skill: Skill) bool + AddCharacteristics(someCharacteristics : params Tuple~string, int~[]) + RemoveCharacteristics(label : string) bool + this~label : string~ : int? } Champion --> "1" LargeImage : Image class ChampionClass{ <> Unknown, Assassin, Fighter, Mage, Marksman, Support, Tank, } Champion --> "1" ChampionClass : Class class Skin{ +/Name : string +/Description : string +/Icon : string +/Price : float } Skin --> "1" LargeImage : Image Champion "1" -- "*" Skin class Skill{ +/Name : string +/Description : string } class SkillType{ <> Unknown, Basic, Passive, Ultimate, } Skill --> "1" SkillType : Type Champion --> "*" Skill class Rune{ +/Name : string +/Description : string } Rune --> "1" LargeImage : Image class RuneFamily{ <> Unknown, Precision, Domination } Rune --> "1" RuneFamily : Family class Category{ <> Major, Minor1, Minor2, Minor3, OtherMinor1, OtherMinor2 } class RunePage{ +/Name : string +/this[category : Category] : Rune? - CheckRunes(newRuneCategory : Category) - CheckFamilies(cat1 : Category, cat2 : Category) bool? - UpdateMajorFamily(minor : Category, expectedValue : bool) } RunePage --> "*" Rune : Dictionary~Category,Rune~ ``` ## Diagramme de classes des interfaces de gestion de l'accès aux données ```mermaid classDiagram direction LR; class IGenericDataManager~T~{ <> GetNbItems() Task~int~ GetItems(index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~T~~ GetNbItemsByName(substring : string) GetItemsByName(substring : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~T~~ UpdateItem(oldItem : T, newItem : T) Task~T~~ AddItem(item : T) Task~T~ DeleteItem(item : T) Task~bool~ } class IChampionsManager{ <> GetNbItemsByCharacteristic(charName : string) GetItemsByCharacteristic(charName : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~ GetNbItemsByClass(championClass : ChampionClass) GetItemsByClass(championClass : ChampionClass, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~ GetNbItemsBySkill(skill : Skill?) GetItemsBySkill(skill : Skill?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~ GetNbItemsBySkill(skill : string) GetItemsBySkill(skill : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~ GetNbItemsByRunePage(runePage : RunePage?) GetItemsByRunePage(runePage : RunePage?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~ } class ISkinsManager{ <> GetNbItemsByChampion(champion : Champion?) GetItemsByChampion(champion : Champion?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Skin?~~ } class IRunesManager{ <> GetNbItemsByFamily(family : RuneFamily) GetItemsByFamily(family : RuneFamily, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Rune?~~ } class IRunePagesManager{ <> GetNbItemsByRune(rune : Rune?) GetItemsByRune(rune : Rune?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~RunePage?~~ GetNbItemsByChampion(champion : Champion?) GetItemsByChampion(champion : Champion?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~RunePage?~~ } IGenericDataManager~Champion?~ <|.. IChampionsManager : T--Champion? IGenericDataManager~Skin?~ <|.. ISkinsManager : T--Skin? IGenericDataManager~Rune?~ <|.. IRunesManager : T--Rune? IGenericDataManager~RunePage?~ <|.. IRunePagesManager : T--RunePage? class IDataManager{ <> } IChampionsManager <-- IDataManager : ChampionsMgr ISkinsManager <-- IDataManager : SkinsMgr IRunesManager <-- IDataManager : RunesMgr IRunePagesManager <-- IDataManager : RunePagesMgr ``` ## Diagramme de classes simplifié du Stub ```mermaid classDiagram direction TB; IDataManager <|.. StubData ChampionsManager ..|> IChampionsManager StubData --> ChampionsManager RunesManager ..|> IRunesManager StubData --> RunesManager RunePagesManager ..|> IRunePagesManager StubData --> RunePagesManager SkinsManager ..|> ISkinsManager StubData --> SkinsManager StubData --> RunesManager StubData --> "*" Champion StubData --> "*" Rune StubData --> "*" RunePages StubData --> "*" Skins ```