Cela fait quelques semaines que je découvre Entity Framework, Le système d’ORM de Microsoft, et je l’apprécie de plus en plus :)

Ce framework d’ORM a beau être jeune et manquer encore de pas mal de fonctions (qui à dit enumérations ?), il simplifie beaucoup la vie, et c’est un vrai plaisir de travailler avec. (tant qu’on a pas besoin d’une fonctionnalité non supportée ^^)

Je ne m’étais jamais intéressé à cette techno plutôt orientée entreprises dans mes projets perso, et je débute donc avec un train de retard, directement avec la version 4.1.

Cette dernière version change et simplifie pas mal de choses lors d’un développement Model First, avec l’ajout de l’API DbContext qui remplace l’ancien ObjectContext.

Lors d’un tel développement, on design notre Entity Model graphiquement, tandis que les classes C# correspondantes, (ainsi que le code SQL de génération de la base de donnée) sont auto-générées.

 

Le passage du modèle Entity aux objets .Net se fait par l’intermédiaire d’un fichier *.tt, un template T4 (Text Template Transformation Toolkit) dont le code, plutôt obscur, ressemble à une page aspx écrite en C#, n’a aucun support de l’intellisense, et ne bénéficie même pas de coloration syntaxique !

 

 

Template par défaut

 

Malheureusement, le code généré par ce template ne possède pas la documentation xml écrite lors de la conception graphique du modèle, et après avoir gentiment demandé à google de me trouver un template déja modifié, sans résultat, j’ai décidé de le faire moi même :)

Code généré par le template “ADO.NET DbContext Generator” par défaut d’Entity Framework 4.1, à partir du modèle Entity :

namespace ModelTrackingV2
{
	using System;
	using System.Collections.Generic;

	public partial class Account
	{
		public Account()
		{
			this.Applications = new HashSet();
		}

		public int Id { get; set; }
		public string Name { get; set; }
		public byte[] PasswordHash { get; set; }
		public string PasswordSalt { get; set; }

		public virtual ICollection Applications { get; set; }
	}
}

 

Comme je vous disais, le code est très propre, mais pas de documentation…

Après quelques recherches, j’ai trouvé ce qu’il me fallait : récupérer la property “Summary” des objets EntityType, et la formater avec les balises xml nécessaires.

 

Modification du template

 

Voici les quelques fonctions que j’ai ajouté au fichier *.tt :

const string XMLCOMMENT_START = "/// ";

string SummaryComment(MetadataItem item)
{
	if (item.Documentation != null && item.Documentation.Summary != null)
	{
		string formattedComment = XMLCOMMENT_START + "<summary>" + Environment.NewLine;
		formattedComment += XMLCOMMENT_START + PrefixLinesOfMultilineComment(XMLCOMMENT_START, XmlEntityize(item.Documentation.Summary));
		formattedComment += Environment.NewLine + XMLCOMMENT_START + "</summary>";
		return formattedComment;
	}
	return string.Empty;
}

void WriteSummaryComment(MetadataItem item)
{
foreach(string line in SummaryComment(item).Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
{
#>
	<#=line#>
<#+
}
}

string PrefixLinesOfMultilineComment(string prefix, string comment)
{
	return comment.Replace(Environment.NewLine, Environment.NewLine + prefix);
}

string XmlEntityize(string text)
{
	if (string.IsNullOrEmpty(text))
	{
		return string.Empty;
	}

	text = text.Replace("<","&lt;").Replace(">","&gt;");
	text = text.Replace("\r", Environment.NewLine).Replace("\n",Environment.NewLine);
	return text;
}

 

L’utilisation est assez simple :

 

//un appel à la fonction écrit le commentaire xml dans le fichier de sortie
WriteSummaryComment(edmProperty);
//la fonction SummaryComment() retourne une string,
//ce sont les balises qui l'entourent qui permettent d'écrire dans le fichier de sortie
<#=SummaryComment(entity)#>

 

Tant que j’y étais, j’en ai profité pour remplacer l’indentation avec espaces, par des tabulations :

 

//un remplacement de ligne suffit :
//PushIndent(CodeRegion.GetIndent(1));
PushIndent("\t");

 

Et voila !
on a maintenant un fichier auto-généré documenté avec le texte indiqué sur le modèle Entity :)

(C’était si dur que ça, Microsoft ? =°)

 

Template modifié

 

Le même objet, documenté cette fois. Vous pouvez remarquer que les commentaires multilignes sont supportés correctement :)

namespace ModelTrackingV2
{
	using System;
	using System.Collections.Generic;
	/// <summary>
	/// permet d'associer un client avec une application,
	/// permet le login
	/// </summary>
	public partial class Account
	{
		public Account()
		{
			this.Applications = new HashSet<Application>();
		}

		public int Id { get; set; }
		public string Name { get; set; }
		/// <summary>
		/// SHA-256 du mot de passe concaténé avec le salt
		/// </summary>
		public byte[] PasswordHash { get; set; }
		/// <summary>
		/// 10 caractères aleatoires
		/// </summary>
		public string PasswordSalt { get; set; }

		public virtual ICollection<Application> Applications { get; set; }
	}
}

 

Attention : le code reste très simple, seule la property “Summary” est prise en compte, la “Long Description” est ignorée.

 

Si vous souhaitez utiliser le template directement : Template final.