Série D'articles:
Introduction
Comme on a vu avec SharePoint designer on peut faire les associations entre les entités de votre BCS afin de mettre en place des vues Master/Details sur des associations. On va reprendre la création de notre BCS fait avec Visual Studio, on va lui ajouter une entité Site et on va faire les changements permettant de l'exploiter, on verra que suite à ces changements, on aura le même comportement qu'avec SharePoint Designer, pour l'instant on recherche le même comportement on verra par la suite les avantages à utiliser Visual Studio.
Avant de continuer on va se pencher sur la description de méthode et de méthode instance :
Modification de l'existant
Premièrement on va supprimer le type descriptor « Site » dans le BDC Explorer.
Puis on va modifier le code des classes pour ne plus retourner « Site » :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BDCRiseCMS.BdcModel1
{
/// <summary>
/// This class contains the properties for Entity1. The properties keep the data for Entity1.
/// If you want to rename the class, don't forget to rename the entity in the model xml as well.
/// </summary>
public partial class RiseDocument
{
//TODO: Implement additional properties here. The property Message is just a sample how a property could look like.
public long DocID { get; set; }
public string MimeType { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Langue { get; set; }
public byte[] Content { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
namespace BDCRiseCMS.BdcModel1
{
/// <summary>
/// All the methods for retrieving, updating and deleting data are implemented in this class file.
/// The samples below show the finder and specific finder method for Entity1.
/// </summary>
public class RiseDocumentService
{
/// <summary>
/// This is a sample specific finder method for Entity1.
/// If you want to delete or rename the method think about changing the xml in the BDC model file as well.
/// </summary>
/// <param name="id"></param>
/// <returns>Entity1</returns>
///
private static SqlConnection getSQLConnection()
{
SqlConnection _cnData;
_cnData = new SqlConnection("Data Source=srvsql; Initial Catalog=CMSRise;User ID=SA; Password=P@ssw0rd;");
_cnData.Open();
return _cnData;
}
public static RiseDocument ReadItem(long docID)
{
RiseDocument rd = new RiseDocument();
using (SqlConnection cndata = getSQLConnection())
{
using (SqlCommand cmdata = new SqlCommand())
{
cmdata.Connection = cndata;
cmdata.CommandText = "SELECT t_cms_u_Document.c_id, t_cms_u_Document.c_u_MimeType, " +
"t_cms_u_Document.c_u_Data, t_cms_u_Content.c_u_Title, t_cms_u_Content.c_u_Description, " +
"t_cms_u_Content.c_u_Language " +
"FROM t_cms_u_Content INNER JOIN t_cms_u_Document ON t_cms_u_Content.c_id = t_cms_u_Document.c_r_Content " +
"where t_cms_u_Document.c_id=@docID";
cmdata.Parameters.AddWithValue("@docID", docID);
SqlDataReader drData = cmdata.ExecuteReader();
if (drData.Read())
{
rd.DocID = drData.GetInt64(0);
rd.MimeType = drData.GetString(1);
rd.Content = (byte[])drData.GetValue(2);
rd.Title = drData.GetString(3);
rd.Description = drData.GetString(4);
rd.Langue = drData.GetString(5);
}
else
{
rd.DocID = -1;
rd.MimeType = "";
rd.Content = null;
rd.Title = "";
rd.Description = "";
rd.Langue = "";
}
}
}
return rd;
}
/// <summary>
/// This is a sample finder method for Entity1.
/// If you want to delete or rename the method think about changing the xml in the BDC model file as well.
/// </summary>
/// <returns>IEnumerable of Entities</returns>
public static IEnumerable<RiseDocument> ReadList()
{
List<RiseDocument> rds = new List<RiseDocument>();
using (SqlConnection cndata = getSQLConnection())
{
using (SqlCommand cmdata = new SqlCommand())
{
cmdata.Connection = cndata;
cmdata.CommandText = "SELECT t_cms_u_Document.c_id, t_cms_u_Document.c_u_MimeType, " +
"t_cms_u_Document.c_u_Data, t_cms_u_Content.c_u_Title, t_cms_u_Content.c_u_Description, " +
"t_cms_u_Content.c_u_Language " +
"FROM t_cms_u_Content INNER JOIN t_cms_u_Document ON t_cms_u_Content.c_id = t_cms_u_Document.c_r_Content ";
SqlDataReader drData = cmdata.ExecuteReader();
while (drData.Read())
{
RiseDocument rd = new RiseDocument();
rd.DocID = drData.GetInt64(0);
rd.MimeType = drData.GetString(1);
rd.Content = (byte[])drData.GetValue(2);
rd.Title = drData.GetString(3);
rd.Description = drData.GetString(4);
rd.Langue = drData.GetString(5);
rds.Add(rd);
}
}
}
return rds;
}
}
}
Maintenant on peut passer à la création de notre entité <Site>
Création de nouvelles entités
On va commencer par le BCS designer :
On va nommer l'entité Site puis on va mettre un nouvelle identifier SiteID :
Sans oublier de mettre le bon type pour SiteID :
On ajoute les deux méthodes ReadList et ReadItem
Pour nous aider a designer les méthodes on utilisera le BDC Method Detail :
On va créer les paramètres pour ReadList :
Voici le contenu, on change le nom du type descriptor et la direction en Return :
Maintenant on va créer notre List Instance
Une Méthode instance permet de spécifier quand utiliser la méthode (retour de l'ensemble des entités, d'une seule entité, mise a jours d'une entité, suppression d'une entité…….)
On specifie le return parameter :
On va faire de même avec ReadItem :
On spécifie le return parameter :
Si l'on regarde dans le solution explorer on se rend compte qu'on n'a pas le site entity mais que le SiteService, on va donc créer la classe Site.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BDCRiseCMS.BdcModel1
{
public class RiseSite
{
public int SiteID { get; set; }
public String SiteName { get; set; }
}
}
Maintenant qu'on l'a créé on peut terminer le schema de notre BCS, dans le BDC explorer on va changer le type des type descriptor SiteRise et SiteRiseList :
Pour SiteRiseList on coche en plus is Enumerable :
SiteID :
On finit l'entité SiteRise :
SiteService a été généré par le designer :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BDCRiseCMS.BdcModel1
{
public partial class SiteService
{
public static IEnumerable<RiseSite> ReadList()
{
throw new System.NotImplementedException();
}
public static RiseSite ReadItem(int ID)
{
throw new System.NotImplementedException();
}
}
}
Avec le code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
namespace BDCRiseCMS.BdcModel1
{
public partial class SiteService
{
private static SqlConnection getSQLConnection()
{
SqlConnection _cnData;
_cnData = new SqlConnection("Data Source=srvsql; Initial Catalog=CMSRise;User ID=SA; Password=P@ssw0rd;");
_cnData.Open();
return _cnData;
}
public static IEnumerable<RiseSite> ReadList()
{
List<RiseSite> lstRS = new List<RiseSite>();
using (SqlConnection cndata = getSQLConnection())
{
using (SqlCommand cmdata = new SqlCommand())
{
cmdata.Connection = cndata;
cmdata.CommandText = "SELECT c_id, c_u_Name FROM t_cms_u_Site" ;
SqlDataReader drData = cmdata.ExecuteReader();
while (drData.Read())
{
RiseSite rs=new RiseSite();
rs.SiteID = (int)drData.GetInt64(0);
rs.SiteName = drData.GetString(1);
lstRS.Add(rs);
}
}
}
return lstRS;
}
public static RiseSite ReadItem(int ID)
{
RiseSite rs = new RiseSite();
using (SqlConnection cndata = getSQLConnection())
{
using (SqlCommand cmdata = new SqlCommand())
{
cmdata.Connection = cndata;
cmdata.CommandText = "SELECT c_id, c_u_Name FROM t_cms_u_Site " +
"where c_id=@ID";
cmdata.Parameters.AddWithValue("@ID", ID);
SqlDataReader drData = cmdata.ExecuteReader();
if (drData.Read())
{
rs.SiteID = drData.GetInt32(0);
rs.SiteName = drData.GetString(1);
}
else
{
rs.SiteID = -1;
rs.SiteName = "";
}
}
}
return rs;
}
}
}
Le résultat une fois la profile page terminé :
Mise en place de l'association
Très bien maintenant passons au plus simple, on va créer une association entre les deux entités, cette association générera une méthode dans chaque entité permettant de faire une vue Master/Details.
On ne remplit rien d'autre, seul le code sera à modifier :
Code dans SIteService
public static IEnumerable<RiseDocument> SiteToRiseDocument(int siteID)
{
List<RiseDocument> rds = new List<RiseDocument>();
using (SqlConnection cndata = getSQLConnection())
{
using (SqlCommand cmdata = new SqlCommand())
{
cmdata.Connection = cndata;
cmdata.CommandText = "SELECT t_cms_u_Document.c_id, t_cms_u_Document.c_u_MimeType, " +
"t_cms_u_Document.c_u_Data, t_cms_u_Content.c_u_Title, t_cms_u_Content.c_u_Description, " +
"t_cms_u_Content.c_u_Language " +
"FROM t_cms_u_Content INNER JOIN " +
"t_cms_u_Document ON t_cms_u_Content.c_id = t_cms_u_Document.c_r_Content INNER JOIN " +
"t_cms_u_Site ON t_cms_u_Content.c_r_Site = t_cms_u_Site.c_id WHERE (t_cms_u_Site.c_id = @siteID) ";
cmdata.Parameters.AddWithValue("@siteID", siteID);
SqlDataReader drData = cmdata.ExecuteReader();
while (drData.Read())
{
RiseDocument rd = new RiseDocument();
if(!drData.IsDBNull(0))
rd.DocID = drData.GetInt64(0);
if (!drData.IsDBNull(1))
rd.MimeType = drData.GetString(1);
if (!drData.IsDBNull(2))
rd.Content = (byte[])drData.GetValue(2);
if (!drData.IsDBNull(3))
rd.Title = drData.GetString(3);
if (!drData.IsDBNull(4))
rd.Description = drData.GetString(4);
if (!drData.IsDBNull(5))
rd.Langue = drData.GetString(5);
rds.Add(rd);
}
}
}
return rds;
}
Code dans RiseDocumentServices :
public static IEnumerable<RiseSite> RiseDocumentToSite(long docID)
{
List<RiseSite> lstRs = new List<RiseSite>();
using (SqlConnection cndata = getSQLConnection())
{
using (SqlCommand cmdata = new SqlCommand())
{
cmdata.Connection = cndata;
cmdata.CommandText = "SELECT t_cms_u_Site.c_id, t_cms_u_Site.c_u_Name "+
"FROM t_cms_u_Content INNER JOIN "+
"t_cms_u_Document ON t_cms_u_Content.c_id = t_cms_u_Document.c_r_Content INNER JOIN "+
"t_cms_u_Site ON t_cms_u_Content.c_r_Site = t_cms_u_Site.c_id WHERE (t_cms_u_Document.c_id = @docID) ";
cmdata.Parameters.AddWithValue("@docID", docID);
SqlDataReader drData = cmdata.ExecuteReader();
while (drData.Read())
{
RiseSite rs = new RiseSite();
rs.SiteID = (int)drData.GetInt64(0);
rs.SiteName = drData.GetString(1);
lstRs.Add(rs);
}
}
}
return lstRs;
}
Le résultat est le suivant :
Le master detail est bien en place. On a donc le même comportement qu'avec SharePoint Designer.
Résultat
Le résultat est proche de SharePoint designer, même si actuellement il est impossible d'indexer ce BCS. Ici on se rend compte que faire la même chose que SharePoint Designer n'est pas si simple avec Visual Studio, cependant à partir de maintenant les possibilités réélles de Visual Studio vont être utilisées.