Conseils et formations : vos deux atouts pour réussir !
Accueil > Linq > Articles
Fonctions de type table avec LINQ

Position du besoin :

Je souhaite faire une page ASP avec les récompenses à donner dans une course à pied.

Mais je dois visualiser toutes les récompenses possibles, qu'elles soient paramétrées pour cette courses ou non.

J'ai déterminé par avance une liste des récompenses que les gestionnaires peuvent donner :

Voici les tables utilisées :

 

Par exemple je dois avoir

Catégorie

Place

Donner cette récompense

CAF

1

Oui

CAF

2

Non

 

Obtenir cette liste est un cas d'utilisation de produit cartésien :

En effet il suffit de faire la combinaison de toutes les récompenses possible et de les joindre (en externe) avec les récompenses données dans la course.

 

La fonction de type table :

 

C'est là que la fonction de type table intervient :

 

Voici le code :

USE [Digitime2008]

create function [dbo].[ftRecompensesParType] (@iNoCourse int)

returns @tRecompense TABLE

(

NoCourse int,

NoTypeRecompense int,

NomTypeRecompense varchar(80),

Categorie varchar(3),

Place smallint,

Gere bit,

NoRecompense int,

NomRecompense varchar(250),

Sponsor varchar(250),

ModeClassement smallint,

DtMajUsr datetime)

as

begin

 

    insert into @tRecompense (NoCourse,NoTypeRecompense,

NomTypeRecompense,Categorie,Place,

Gere,NoRecompense,NomRecompense,Sponsor,ModeClassement,DtMajUsr)

    select    rca.NoCourse as NoCourse,

            rca.NoTypeRecompense as NoTypeRecompense,

            tr.Libelle as NomTypeRecompense,

            rca.Categorie as Categorie,

            rca.Place as Place,

    case when rcc.NoRecompense is null then 0

        else 1

    end as Gere,

    rcc.NoRecompense as NoRecompense,

    rcc.NomRecompense as NomRecompense,

    rcc.Sponsor as Sponsor,

    rcc.ModeClassement as ModeClassement,

    rcc.DtMajUsr as DtMajUsr

     from

     (select @iNoCourse as NoCourse,2 as NoTypeRecompense,Categorie, p.Place as Place from dbo.Categorie

    cross join

    dbo.ftPlagesDePlaces (1,3) p

    where NoCourse = @iNoCourse

    ) rca

    left outer join Recompense rcc

    on    rca.NoCourse = rcc.NoCourse and

        rca.NoTypeRecompense = rcc.NoTypeRecompense and

        rca.Categorie = rcc.Categorie and

        rca.Place = rcc.Place

    left outer join TypeRecompense tr

    on rca.NoTypeRecompense = tr.NoTypeRecompense

union

    select    rca.NoCourse as NoCourse,

            rca.NoTypeRecompense as NoTypeRecompense,

            tr.Libelle as NomTypeRecompense,    

            rca.Categorie as Categorie,

            rca.Place as Place,

    case when rcc.NoRecompense is null then 0

        else 1

    end as Gere,

    rcc.NoRecompense as NoRecompense,

    rcc.NomRecompense as NomRecompense,

    rcc.Sponsor as Sponsor,

    rcc.ModeClassement as ModeClassement,

    rcc.DtMajUsr as DtMajUsr

     from

     (select @iNoCourse as NoCourse,4 as NoTypeRecompense,null as Categorie, p.Place as Place from

    dbo.ftPlagesDePlaces (1,8) p

    ) rca

    left outer join Recompense rcc

    on    rca.NoCourse = rcc.NoCourse and

        rca.NoTypeRecompense = rcc.NoTypeRecompense and

        rca.Place = rcc.Place

    left outer join TypeRecompense tr

    on rca.NoTypeRecompense = tr.NoTypeRecompense

union

    select    rca.NoCourse as NoCourse,

            rca.NoTypeRecompense as NoTypeRecompense,

            tr.Libelle as NomTypeRecompense,    

            rca.Categorie as Categorie,

            rca.Place as Place,

    case when rcc.NoRecompense is null then 0

        else 1

    end as Gere,

    rcc.NoRecompense as NoRecompense,

    rcc.NomRecompense as NomRecompense,

    rcc.Sponsor as Sponsor,

    rcc.ModeClassement as ModeClassement,

    rcc.DtMajUsr as DtMajUsr

     from

     (select @iNoCourse as NoCourse,5 as NoTypeRecompense,null as Categorie, p.Place as Place from

    dbo.ftPlagesDePlaces (1,8) p

    ) rca

    left outer join Recompense rcc

    on    rca.NoCourse = rcc.NoCourse and

        rca.NoTypeRecompense = rcc.NoTypeRecompense and

        rca.Place = rcc.Place

    left outer join TypeRecompense tr

    on rca.NoTypeRecompense = tr.NoTypeRecompense

 

    return

end

 

 

Explications :

J'ai utilisé une autre fonction de type table qui me donne des places de places entre deux valeurs :

 

function [dbo].[ftPlagesDePlaces](@iPremierePlace int,@iDernierePlace int)

returns @tPlace TABLE

(

Place int NOT NULL

)

AS

begin

    declare @Place int

    set @Place = @iPremierePlace

    while @Place <= @iDernierePlace

        begin

            insert into @tPlace (Place) values (@Place)

            set @Place = @Place + 1

        end

return

end

 

Ce genre de fonction est très pratique pour tout un tas de choses…

Voilà donc ma partie SQL terminée : j'ai une liste de toutes les récompenses possibles avec un indicateur (Gere de type bit) qui me dit si cette récompense est donnée dans cette course.

 

 

Passage à la partie LINQ :

Là, je dois avouer que j'ai du m'y reprendre à trous fois pour arriver à l'objectif :

  1. Au lieu de ma fonction de type table, j'utilisais une procédure stockée : échec car le rendu est un single result (dionc une ligne) par défaut. Je me suis fixé comme règle de ne pas réécrire la définition des objets LINQ
  2. J'ai fait une fonction de type table en ligne (toujours sur la même requête vue ci-dessus) : nouvel échec, le type des données en retour étant aléatoire (je ne sais toujours pas comment LINQ déternie à la volée les types de données d'un SELECT)
  3. Je suis arrivé à la fonction typée vue plus haut, qui elle ne pose aucun problème

 

Une fois écrit dans SQL, l'utilisation avec LINQ n'est que du bonheur !

La définition :

 

 

L'utilisation au sein d'un objet métier :

 

/// <summary>

/// Rend toutes les Recompenses d'une course

/// </summary>

/// <returns></returns>

public static List<ClRecompense> LireRecompenses(int iNoCourse)

{

try

{

List<ClRecompense> tClRecompense = new List<ClRecompense>();

 

DataClassesDataContext db = new DataClassesDataContext();

 

 

var Recompenses = from r in db.ftRecompensesParType(iNoCourse)

orderby r.NoTypeRecompense,r.Categorie, r.Place

select r;

if (Recompenses.Count() < 1)

return tClRecompense;

foreach (var lnqR in Recompenses)

{

ClRecompense clR = new ClRecompense();

clR.NoRecompense = Utilitaires.NullEnInt(lnqR.NoRecompense);

if (lnqR.NoRecompense != null)

clR.Gerer = true;

else

clR.Gerer = false;

 

clR.NoCourse = Utilitaires.NullEnInt(lnqR.NoCourse);

clR.Categorie = Utilitaires.NullEnString(lnqR.Categorie);

clR.NoTypeRecompense = Utilitaires.NullEnInt(lnqR.NoTypeRecompense);

clR.NomTypeRecompense = Utilitaires.NullEnString(lnqR.NomTypeRecompense);

clR.NomRecompense = Utilitaires.NullEnString(lnqR.NomRecompense);

clR.Place = Utilitaires.NullEnInt16(lnqR.Place);

clR.Sponsor = Utilitaires.NullEnString(lnqR.Sponsor);

clR.ModeClassement = Utilitaires.NullEnInt16(lnqR.ModeClassement);

clR.DtMajUsr = Utilitaires.NullEnDateTime(lnqR.DtMajUsr);

 

tClRecompense.Add(clR);

}

 

return tClRecompense;

}

catch (Exception Erreur)

{

throw new Exception("LireRecompenses " + Erreur.Message);

}

}

 

L'utilisation de cet objet métier au sein d'une page ASP :

 

Le paramètre étant attrapé à la volée ici :

 

protected void odsRecompenses_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)

{

try

{

if (AssistantValidation.ActiveStepIndex == 3)

e.InputParameters["iNoCourse"] = this.clCourse.NoCourse;

else

e.InputParameters["iNoCourse"] = -1;

 

}

catch (Exception Erreur)

{

Label lblErreur = (Label)Master.FindControl("lblErreur");

lblErreur.Text = "odsRecompenses_Selecting " + Erreur.Message;

}

 

}

 

On voit bien dans ce post la tendance de l'informatique actuelle :

Une combinaison de technologies qui permet avec le minimum d'efforts et le maximum de maintenabilité d'arriver au résultat.

 ‭(Masqué)‬ WebPart1 Web Part

/Linq/Fonctions de type table avec LINQ/