Architecture Silverlight LOB – Concepts et technologies (Partie 4)

Dans ce post je vais commencer avec un simple « Business Domain Model » et je vais crée une couche de domain autour du modele.

Dans cet exemple notre application sera une application Web pour une société qui vend des produits et cela peut être utilisé par ses clients pour faire des commandes et ses salariés pour les traiter. Ces commandes ont les détails qui consistent en produits et des quantités. Chaque produit peut avoir une catégorie de produit. Quand un client soumet une commande, un salarié de la société peut traiter cet commande et préparer les articles pour l’expédition.

La société a quelques départements et chaque salarié appartient à un département. Cela signifie que les salariés du Service des ventes devront traiter les commandes; les salariés du département de Ressources Humain pourront recruter de nouveaux salariés; et les salariés du Département Financier pourront observer quelques diagrammes et des rapports avec la statistique comment les ventes se développent en fonction du temps, des rapports de ventes, etc.

l’authentication et l’authorization seront ajoutés plutard.

Pour faire simple, j’ai créent le modèle de données suivant :

modele

Ce modèle sera tant notre modèle de données que le modèle de domaine. C’est très simple et comme j’ai dit au poste précédent, créant un modèle de domaine séparé est facultatif parce que vous pouvez toujours faire bien avec vos entités de données. Puisque nous utilisons la « Entity FRamework » nous profiterons de LinqToEntitiesDomainService, un Service de Domaine spécifique qui traite avec les objets de l’EF.

Puisque nous commençons par notre couche de Domaine, nous définirons un Service de Domaine qui peut être utilisé de notre application Silverlight (ou d’autres clients aussi) et créer les opérations CRUD (creation, mise à jour, suppression). Je suis sûr que vous avez remarqué combien de code est produit quand vous utilisez le modèle de Service de Domaine de visual Studio. Créez juste une classe de base pour vos services de domaine et ajoutez les méthodes suivantes :

#region Basic CRUD
protected IQueryable<T> GetQuery<T>()
    where T : class
{
    return this.GetRepository<T>().GetQuery();
}
protected void Insert<T>(T entity)
    where T : class
{
    this.GetRepository<T>().Add(entity);
}
protected void Update<T>(T entity)
    where T : class
{
    this.GetRepository<T>().AttachAsModified(entity, this.ChangeSet.GetOriginal(entity));
}
protected void Delete<T>(T entity)
    where T : class
{
    this.GetRepository<T>().Delete(entity);
}
#endregion
 
protected IRepository<T> GetRepository<T>()
    where T : class
{
    return this.Container.Resolve<IRepository<T>>();
}

La propriété conteneurs est un cas IUNITYCONTAINER, que jegarde dans le Service de Domaine de base. J’ai d’habitude d’une classe singleton commune où le conteneur IoC est disponible mais je crée aussi un conteneur enfant pour chaque Service de Domaine. Cela me permet d’enregistrer des cas spécifiques dans le conteneur enfant et l’utiliser seulement dans les limites de mon Service de Domaine. C’est utile pour résoudre des repositories parce que mes repositories dépendent de l’ObjectContext qui est injecté via l’injection de dépendance. Voici comment on procède :

public abstract class DomainRepositoryService<TContext> : LinqToEntitiesDomainService<TContext>, IDbContextManager
    where TContext : ObjectContext, IDbContext, new()
{
    protected IUnityContainer Container { get; private set; }
    /// <summary>
    /// Create a child container to use THIS as the IDbContextManager implementation when resolving repositories
    /// Ensures that other threads / domain services can use the main container to resolve repositories
    /// and use its own instance as the IDbContextManager for the repositories they need
    /// </summary>
    /// <param name="context">The DomainServiceContext instance</param>
    public override void Initialize(DomainServiceContext context)
    {
        base.Initialize(context);
 
        this.Container = IoC.Current.Container.CreateChildContainer();
        this.Container.RegisterInstance<IDbContextManager>(this);
    }
 
    #region IDbContextManager Members
    public IDbContext GetDbContext()
    {
        return this.ObjectContext;
    }
    #endregion
    //...
}

Cela a dit, le Service de Domaine spécifique pour notre application Silverlight y ressemblera :

[EnableClientAccess()]
public class MyAppService : DomainRepositoryService<MyAppEntities>
{
    #region Customer
    public IQueryable<Customer> GetCustomers()
    {
        return base.GetQuery<Customer>();
    }
    public void InsertCustomer(Customer entity)
    {
        base.Insert(entity);
    }
    public void UpdateCustomer(Customer entity)
    {
        base.Update(entity);
    }
    public void DeleteCustomer(Customer entity)
    {
        base.Delete(entity);
    }
    #endregion
    //repeat for the other entities...
}

Remarquez comment ma Couche de Domaine ne se soucie pas vraiment de comment les entités sont stockées ou gérées avec EF (entity framework). Il le délègue la responsabilité à un objet qui met en oeuvre l’interface IREPOSITORY.

Cette interface peut être générique et ressemble souvent :

public interface IRepository<TEntity>
    where TEntity : class
{
    TEntity GetEntity(int id);
    IQueryable<TEntity> GetQuery();
    void Add(TEntity entity);
    void Update(TEntity entity);
    void Delete(TEntity entity);
    /// <summary>
    /// Abstraction on RIA's AttachAsModified extension method
    /// </summary>
    /// <param name="current"></param>
    /// <param name="original"></param>
    void AttachAsModified(TEntity current, TEntity original = null);
}

Pour la simplicité j’ai inclus la méthode AttachAsModified dans l’IREPOSITORY. Cette méthode est importante parce que RIA exige que l’entité actuelle étant mise à jour soit attachée dans l’ObjectContext. Une autre option devrait créer une interface séparée qui provient d’IREPOSITORY et ajouter la méthode là. C’est que l’interface IREPOSITORY est un concept générique qui peut être utilisé avec beaucoup de technologies d’accès de données.

Notez que du moment vous créez votre Service de Domaine et exposez vos entités, imediatement une autre personne/équipe peut commencer à construire l’application utilisant les entités exposées, tandis qu’une autre équipe continue à travailler sur la couche serveur ajoutant des métadonnées et-ou la logique de validation qui sera aussi disponible pour l’application client.

Suite : prochain poste

PS : cet article est une adaptation en français d’une suite d’articles par Manuel Felício

Kamel DJELLAL
Chef de projet
EDIS CONSULTING – GROUPE UBISIDE

http://www.ubiside.fr/

Laisser un commentaire