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 :
- 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
- 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)
- 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.