// ========================================================================
//
// Copyright (C) 2016-2017 MARC CHEVALDONNE
//                         marc.chevaldonne.free.fr
//
// Module        : Program.cs
// Author        : Marc Chevaldonné
// Creation date : 2016-11-01
// Mise à jour   : 2017-09-18
//
// ========================================================================

using System;
using System.Collections.Generic;
using static System.Console;

namespace ex_042_012_EF_CF_Dictionary
{
    /// <summary>
    /// L'utilisation de dictionnaires est "déconseillée" lors de l'utilisation d'Entity Framework par les utilisateurs car ils ne sont pas gérés par EF comme une relation entre entités.
    /// Personnellement, je n'aime pas que le choix d'une technologie apporte des contraintes sur mon modèle. 
    /// Voici donc une proposition de solution quant à l'utilisation de dictionnaires dans votre modèle.
    /// Elle est certes moins efficace que si vous n'utilisez que des collections car elle nécessite des projections. 
    /// Son avantage est de ne pas vous obliger à modifier votre modèle. Pour cela :
    /// 1) j'utilise deux nouvelles classes : NounoursEx et LitEx qui sont des procurateurs sur Nounours et Lit,
    /// 2) le dictionnaire Dictionary<Nounours, int> dans Lit est transformé en deux relations :
    ///     a) une relation one to many entre Lit et une nouvelle classe Score
    ///     b) une relation one to one entre Score et Nounours
    ///     De plus, Score contient non seulement le Nounours qui servait de clé dans le dictionnaire, mais également la valeur qui était associée à cette clé.
    /// 3) la classe NounoursDBEntities (le DBContext) possède deux méthodes GetAll et AddAll permettant respectivement de récupérer des Nounours et des Lits à partir des entités de NounoursEx, LitEx et Score,
    /// et d'ajouter dans la base des nounours et des lits en les projetant en entités de types NounoursEx, LitEx et Score.
    /// 
    /// Pour finir, j'ai cherché à mettre en oeuvre une solution plus élégante et plus rapide à écrire avec Entity Framework 7. Celle-ci se base sur l'utilisation des shadow properties et de la réécriture des méthodes
    /// du DbContext pour permettre la transformation du dictionnaire en collections. Malheureusement, cette solution ne peut pas être utilisée aujourd'hui car les shadow properties ne peuvent pas être des collections 
    /// dans Entity Framework Core. Espérons qu'il sera possible dans la prochaine version d'EF Core d'utiliser des shadow properties de type collections, ou mieux, que les dictionnaires soient gérés par EF Core et
    /// directement transformés en relations !
    /// </summary>
    public class Program
    {
        public static void Main(string[] args)
        {
            //création du DbContext et injection de la dépendance à MyStubDataInitializationStrategy
            using (NounoursDBEntities db = new NounoursDBEntities())
            {
                //choix de la stratégie et remplissage avec des données stubbées
                DbContextInitializer.Seed(db);

                WriteLine("Récupération des données sans passer par les classes Model :\n");

                WriteLine("nounours : ");
                foreach (var n in db.NounoursSet/*.Include("Score")*/)
                {
                    WriteLine($"\t{n} - Score: {n.Score.Value}");
                }

                WriteLine("lits : ");
                foreach (var l in db.LitsSet)
                {
                    WriteLine($"\t{l.Propriétaire}");
                    foreach (var kvp in l.Scores)
                    {
                        WriteLine($"\t\t{kvp.Key.Nom}: {kvp.Value}");
                    }
                }

                WriteLine("\n\nRécupération des données en passant par une projection dans les classes du Model :\n");


                if (!db.GetAll(out var lits, out var nounours))
                {
                    Console.WriteLine("oups... la projection a échoué.");
                }

                WriteLine("nounours : ");
                foreach (var n in nounours)
                {
                    WriteLine($"\t{n}");
                }

                WriteLine("lits : ");
                foreach (var l in lits)
                {
                    WriteLine($"\t{l.Propriétaire}");
                    foreach (var kvp in l.Scores)
                    {
                        WriteLine($"\t\t{kvp.Key.Nom}: {kvp.Value}");
                    }
                }
            }
        }
    }
}
