C# 基本实体类。亚硝酸铵

C# 基本实体类。亚硝酸铵,c#,nhibernate,interface,entity,C#,Nhibernate,Interface,Entity,这样实现实体基类是否是一种好的做法: [Serializable] public abstract class Entity<T> : IComparable<Entity<T>>, IFormattable { public abstract Int32 CompareTo(Entity<T> entity); public abstract String ToString(String format, IFormatProvid

这样实现实体基类是否是一种好的做法:

[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、IFormattable
{
公共摘要Int32 CompareTo(实体);
公共抽象字符串到字符串(字符串格式,IFormatProvider);
// ...
}
因此,所有派生类都必须实现这些接口。 将
IComparable
接口放在实体类上是否合理?
谢谢

如果您的实体需要可比性和格式,那么使用基类是非常好的做法。 有时,标识字段也在基类中实现。

这不是一个好的(或坏的)实践-它完全取决于您的需要

在常规级别指定
IComparable
,可能会带来这样的风险,即在继承链的较低位置比较某些对象可能没有意义。即使你能比较两个物体,它也总是有意义的吗?您可能需要编写几行代码来满足一个永远不会使用的契约——请注意


然而,若您需要创建一个绝对契约,以便可以比较从实体继承的任何对象,那个么这将是很好的。这允许您在代码中做出积极的假设。

什么是不可能的?您的域类?如果是这样的话,为什么不让实体类成为非泛型类并直接从实体继承呢

一般来说,我发现从公共接口或基类派生特定存储库可以处理的所有域类是一种好的做法。这允许存储库是该接口的通用接口,提供编译时检查,以确定您正试图使用存储库来持久化存储库已映射的内容。但是,如果您使用基类,除非您需要一种方法来唯一地标识任何实体,而不管其实际的子类类型如何,否则不要映射它;否则,您会将该实体表(带有任何公共字段)作为数据库中的一个表,并且很难通过数据层手动跟踪

然而,可能需要一个通用的映射实体;您可能希望通过公共ID列唯一地标识个人和公司,即使个人和公司保存到不同的表中,该列也是唯一的

下面是我在一个项目中使用的层次结构的一个消毒示例:

//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> { ... }
//将类标识为可持久的,并要求该类指定
//其主键的标识列
公共接口IDomainObject{long Id{get;}}
//在每个数据库模型的存储库中,仅仅因为它是IDOMain对象并不意味着
//回购协议可以与之配合。因此,我进一步推导,以创建基本的“标记”
//将域对象标识为来自特定数据库的接口:
公共接口ISecurityDomainObject:IDomainObject{}
公共接口IDataDomainObject:IDomainObject{}
公共接口IData2DomainObject:IDomainObject{}
//您的repo或DB中可能有逻辑来防止某些并发问题。
//您可以指定域对象具有版本检查所需的字段
//在IDOMAIN对象级别、较低级别或独立地向上:
公共接口IVersionedDomainObject:IDomainObject
{ 
长版本{get;}
字符串lastUpdateBy{get;}
DateTime LastUpdateDate{get;}
}
//现在,您可以使用这些接口将回购限制为
//基于每个对象持久化到的数据库的完整域:
公共接口i位置,其中TDom:idomain对象
{
//是的,GTP可以用作GTC
T GetById(长Id),其中T:TDom;
无效保存(T obj),其中T:TDom;
//SaveVersioned()的域类不仅必须实现TRest,
//它必须是可版本的
void SaveVersioned(T versionedObj),其中T:TDom,IVersionedDomainObject
}
//现在你可以把TDom关闭到一个界面上,这个界面限制了混凝土
//可以传递给repo的泛型方法的类:
公共类ISecurityRepo:IRepository{…}

是的,我知道如何保留Id(上面的类定义为泛型,因此它可以使用wheter Int32或Id的Guid类型)和重写/实现
Equals
方法。还有,谢谢!