4 votes

Classe d'entité de base. NHibernate

Serait-ce une bonne pratique que d'implémenter une classe de base d'entité comme celle-ci :

[Serializable]
public abstract class Entity<T> : IComparable<Entity<T>>, IFormattable
{
    public abstract Int32 CompareTo(Entity<T> entity);
    public abstract String ToString(String format, IFormatProvider provider);

    // ...
}

Toutes les classes dérivées doivent donc implémenter ces interfaces. Est-il raisonnable de mettre IComparable<T> sur la classe d'entité ? Merci de votre compréhension.

3voto

christofr Points 1348

Il ne s'agit pas d'un bon (o mauvais ) - cela dépend entièrement de vos besoins.

Préciser IComparable à un niveau aussi général comporte le risque que la comparaison de certains objets situés plus bas dans la chaîne d'héritage n'ait pas de sens. Même s'il est possible de comparer deux objets, est-il toujours utile de le faire ? Vous risquez d'exiger l'écriture de lignes de code pour satisfaire un contrat qui ne sera jamais utilisé. Circonstances de YAGNI .

Cependant, cela conviendrait si vous deviez créer un contrat absolu afin que tous les objets héritant d'Entity puissent être comparés. Cela vous permet de faire des hypothèses positives dans votre code.

2voto

KeithS Points 36130

Que serait T ? Votre classe de domaine ? Si c'est le cas, pourquoi ne pas rendre la classe Entity non générique et hériter directement d'Entity ?

En général, j'ai trouvé que c'était une bonne pratique de dériver toutes les classes de domaine qui peuvent être gérées par un référentiel particulier à partir d'une interface commune ou d'une classe de base. Cela permet au référentiel d'être générique à cette interface, en vérifiant à la compilation que vous essayez d'utiliser le référentiel pour persister quelque chose que le référentiel a mis en correspondance. Si vous utilisez une classe de base, cependant, ne la mappez pas à moins que vous n'ayez besoin d'un moyen d'identifier de manière unique toute entité indépendamment de son type de sous-classe réel ; sinon, vous obtiendrez cette table d'entité (avec tous les champs communs) en tant que table dans votre base de données et il peut devenir difficile de tracer manuellement à travers votre couche de données.

Toutefois, il peut être souhaitable d'utiliser une entité commune et mappée ; vous pouvez vouloir identifier les personnes et les entreprises par une colonne ID commune qui est unique, même si les personnes et les entreprises sont enregistrées dans des tables différentes.

Voici un exemple stérilisé de la hiérarchie que j'ai utilisée dans l'un de mes projets :

//identifies a class as persistable, and requires the class to specify 
//an identity column for its PK
public interface IDomainObject { long Id {get;} } 

//In a repository-per-DB model, just because it's an IDomainObject doesn't mean
//a repo can work with it. So, I derive further to create basically "marker"
//interfaces identifying domain objects as being from a particular DB:
public interface ISecurityDomainObject:IDomainObject { }
public interface IDataDomainObject:IDomainObject { }
public interface IData2DomainObject:IDomainObject { }

//There may be logic in your repo or DB to prevent certain concurrency issues.
//You can specify that a domain object has the necessary fields for version-checking
//either up at the IDomainObject level, a lower level, or independently:
public interface IVersionedDomainObject:IDomainObject
{ 
   long Version {get;}
   string LastUpdatedBy {get;}
   DateTime LastUpdatedDate {get;}
}

//Now, you can use these interfaces to restrict a Repo to a particular subset of
//the full domain, based on the DB each object is persisted to:

public interface IRepository<TDom> where TDom:IDomainObject 
{
    //yes, GTPs can be used as GTCs
    T GetById<T>(long Id) where T:TDom;
    void Save<T>(T obj) where T:TDom;

    //not only must the domain class for SaveVersioned() implement TRest,
    //it must be versionable
    void SaveVersioned<T>(T versionedObj) where T:TDom, IVersionedDomainObject
}

//and now you can close TDom to an interface which restricts the concrete
//classes that can be passed to the generic methods of the repo:

public class ISecurityRepo:IRepository<ISecurityDomainObject> { ... }

0voto

Variant Points 7827

Si vos entités doivent être comparables et formatées, l'utilisation d'une classe de base est une très bonne pratique. Parfois, le champ d'identité est également implémenté dans la classe de base.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X