您的位置:首页 > 其它

后台管理框架之四 :数据模型设计

2014-09-21 15:09 423 查看
  当项目完成整体构建之后,接下来的工作就是对针对性的进行各方面的设计。整个项目的设计包括很多方面,比如数据持久化的设计、页面View处理的设计、业务逻辑的设计等。今天我们先来确定数据模型的设计。

  数据持久化部分包括两块,一块是数据操作部分,一块是数据模型部分。而核心的数据持久化部分,如SQL语句拼写、参数定义等,因为采用EF框架,很多工作都由它做了,不需要我们过多的考虑。今天我们先来确定据模型部分。

  任何一个项目需要处理的数据无外乎包括两类:

  1、前台数据:由用户通过前台View操作而产生或改动的数据,主要与业务相关,如用户数据、机构数据等。对于这类信息,我们一般会要求记录谁创建、谁最后修改、什么时候创建、什么时候最后修改等。可能还有一些扩展需求就是:某类数据禁止物理删除,如用户数据,很多业务数据与用户相关,一般不应做实际物理删除;数据需要进行共享,需要被其它业务系统进行抽取等;

  2、后台数据:系统自动记录的数据,如异常信息、驱动消息、用户轨迹等。对于这类信息,都是由系统自动记录,人为不参与,不会涉及到谁创建或谁修改等等问题。

  有一种数据比较特殊,就是解决多对多关系而扩展的关联表数据,如用户和角色的多对多关系,对这类表一般是直接定义双主键、双字段。这类关系确实因用户前台View操作而产生,但它仅存储关联关系,并不存储实际的业务数据,而且需要用两个主键来唯一确定一条对应关系。这类数据设计可自由裁量。

  另外,在数据模型设计时,一般为了方便都会进行一定的限定,确保这些实体都有一个统计的规范,所以采用空接口进行相应限定。即使是空接口的限定,对于泛型编程来说也是较为重要的,可以有效地限制非数据模型的泛型实体定义,减少出现不可知的问题。

  按照以上的思路,项目的数据模型会按以下结构进行设计:

  


  

  通过以上模型定义,基本可以将本项目中涉及的数据进行了定义,后续各个实体数据模型可根据实际情况分别从BaseFOPEntity、BaseBOPEntity、BaseROPEntity中进行继承。其中有几点需要提到的是:

  1、IEntity接口中的PrimaryKey接口是用来确定当前实体模型主键列名的。项目中页面视图采用EasyUi datagrid组件,列表基本上都涉及到分页功能,而Linq To Entity的分页排序需要指定一个排序键,所以在做Repository设计时提供了默认的排序键,就是当前实体的主键。

  2、BaseObject抽象类中,采用了泛型的ID定义,主要是不太想限制数据模型的主键类型,所有实现类可以重新定义实体模型的主键类型,提高实体模型的灵活性。采用ID列定义,还有一个好处就是,如果数据模型没有定义其它Key属性、Id列的数据类型可转化为Int、采用SqlServe数据库(支持自增列),EF会自动将Id列设置为自增列主键。而ColVersion列采用的TimeSpan类型,一个表中最多仅能有一个TimeSpan列类型,任何一次的新增或修改数据库系统都会自动增量修改其值,而且TimeSpan列值不允许用户进行修改。此列正好是做为行数据变动的标志。

  以下是BaseObject的代码:

using System;
using System.ComponentModel.DataAnnotations;

namespace EPF.linxy.Data.Model.Base
{
/// <summary>
/// 关系型数据模型父类
/// </summary>
/// <typeparam name="Tid">
/// 实体数据模型的泛型定义
/// </typeparam>
[Serializable]

public abstract class BaseObject<Tid> : IEntity , IEquatable<BaseObject<Tid>>
{
private object _id;
private string _key;
/// <summary>
/// 主键定义
/// 可由实现类重写
/// </summary>
[Key]
public virtual Tid Id
{
get
{
//根据主键类型生成默认的主键值
if ( _id == null && typeof( Tid ) ==  typeof( Guid ) )
_id = Guid.NewGuid();
return _id == null ? default( Tid ): (Tid)_id;
}
set { _id=value; }
}

/// <summary>
/// 行数据变动标识
/// 在实体模型中必须将其定义为Byte[]类型,否则无法写入表
/// </summary>
[Timestamp]
public Byte[ ] TimeSpan { get; set; }

public bool Equals(BaseObject<Tid> other)
{
return Id.Equals( other.Id );
}

public virtual string PrimaryKey()
{
return _key = _key??GenerateKeyName();
}

/// <summary>
/// 默认的生成实体模型主键名称的定义
/// 目前未做多主键的生成
/// </summary>
/// <returns></returns>
private string GenerateKeyName()
{
foreach ( var p in this.GetType().GetProperties() )
{
foreach ( var k in p.GetCustomAttributes( false ) )
{
if ( k is KeyAttribute )
return p.Name;
}
}

return String.Empty;
}

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐