Базовый класс сущности. NHibernate - PullRequest
4 голосов
/ 31 октября 2011

Будет ли хорошей практикой реализовать базовый класс сущностей следующим образом:

[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);

    // ...
}

Таким образом, все производные классы должны реализовывать эти интерфейсы. Разумно ли ставить IComparable<T> интерфейс на класс сущности? Спасибо!

Ответы [ 3 ]

3 голосов
/ 31 октября 2011

Это не хорошая (или плохая ) практика - она ​​полностью зависит от ваших потребностей.

Указание IComparable на общем уровне сопряжено с риском того, что может не иметь смысла сравнивать некоторые объекты далее в цепочке наследования. Даже если вы можете сравнить два объекта, всегда ли это имеет смысл? Возможно, вы потребуете написания строк кода, чтобы утвердить контракт, который никогда не будет использован - остерегайтесь обстоятельств YAGNI .

Однако это было бы хорошо, если вам нужно создать абсолютный контракт, чтобы можно было сравнивать любые объекты, наследуемые от Entity. Это позволяет вам делать положительные предположения в вашем коде.

2 голосов
/ 31 октября 2011

Что бы Т было? Ваш домен класса? Если это так, почему бы не сделать класс Entity неуниверсальным и напрямую наследовать от Entity?

В целом я считаю хорошей практикой выводить все классы предметной области, которые могут обрабатываться конкретным репозиторием, из общего интерфейса или базового класса. Это позволяет репозиторию быть универсальным для этого интерфейса, обеспечивая проверку во время компиляции, что вы пытаетесь использовать репозиторий для сохранения чего-то, что репозиторий отобразил. Однако, если вы используете базовый класс, не отображайте его, если вам не нужен способ уникальной идентификации любого объекта независимо от его фактического типа подкласса; в противном случае вы получите эту таблицу сущностей (с любыми общими полями) в виде таблицы в вашей БД, и вам может быть сложно вручную проследить через уровень данных.

Однако может быть желательным общее сопоставленное Сущность; Возможно, вы захотите однозначно идентифицировать лиц и компаний с помощью общего столбца идентификаторов, который уникален даже для лиц и компаний, сохраненных в разных таблицах.

Вот стерилизованный пример иерархии, которую я использовал в одном из моих проектов:

//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> { ... }
0 голосов
/ 31 октября 2011

Если ваши объекты требуют сопоставимости и форматирования, тогда использование базового класса - очень хорошая практика. иногда поле идентификатора также реализуется в базовом классе.

...