现在的位置: 首页 > 综合 > 正文

XY-ORM 教程二:ORM关系配置

2012年12月20日 ⁄ 综合 ⁄ 共 4126字 ⁄ 字号 评论关闭

上次我们学习了基本的框架配置以及实体的增删改查,接下来,我们将学习第二个课程:细化ORM关系配置。

教程二主要包含以下内容:

1 表配置;

2 常规列配置(int、string、datetime、byte、char、double、decimal等数据库原本就支持的);

3 枚举列配置;

4 布尔型配置;

5 用于一般性验证的列属性配置;

6 延迟加载配置;

7 主外键关系配置;

8 自定义输出列配置;

 

用过NHibernate、MyBaits等框架的同胞们就知道,表与实体的关系配置都是在单独的配置文件完成的,但是祥亿认为这样有一个比较不好的地方,就是配置文件多,稍微输入一个错误字符导致项目启动失败的时候,调试困难;所以祥亿在尽量提高调试的目标下,选择了.NET的自定义特性来完成表与实体的关系配置,并提供了很智能的出错提示(比如:列不存在,列类型与属性类型不匹配)。

 好了,废话说少,先看下最基本的表配置以及列配置:

View Code

/// <summary>
/// 实体的配置说明
/// </summary>
配置1:[Table("TestPz")] // 这种情况,是只配置表的名称
配置2:[Table("TestPz","配置表")] // 这种情况,配置了表的名称,以及表的中文名(配置表中文名的好处在于提示信息的时候)
public class TestPz
{
配置1:[Column("Name")]
配置2:[Column("Name","名称")]// 同时给定列名,用于提示信息
public string Name { get; set; }

   基本配置只需要配置实体对应的表名,属性对应的列名。而不需要关心是否要配置是否主键以及列类型,列长度等信息。(在数据访问层会通过数据库的结构查询得到各个列的类型等信息。)

  对于有些常用的属性类型,比如:枚举、布尔,数据库没有原生的类型相匹配。有些框架通过以下的方式进行转换:

 枚举:
    // 用于页面调用 
    public Sex Sex
{
get
{
return (Sex)Enum.Parse(typeof(Sex), this.SexValue);
}
set
{
this.SexValue = value.ToString();
}
}
    // 用于保存到数据库的值

public string SexValue { get; set; }
布尔:

     public bool IsVip
{
get
{
return IsVipValue == 1;
}
set
{
this.IsVipValue = value ? 1 : 0;
}
}

public int IsVipValue { get; set; }
祥亿平台完全支持这两种类型的配置:
    // 数据库的列类型为字符串类型的即可。
[Column("Sex")]
public Sex Sex { get; set; }
// 数据库的列类型为bool(数据库原生支持的),或者为整型(1表示true;0表示false)
[Column("IsVip")]
public bool IsVip { get; set; }

 


接下来,我们来看下如何通过配置来达到基本的验证

 

基本的验证包括:值是否为空、长度验证、最大最小值验证。

 

public class TestEo : BaseEo
{
       // 创建时间,验证类型:不能为空
[Column("CreateTime", "创建时间", false)]
public DateTime CreateTime { get; set; }

// 账号,验证类型:不能为空,并且长度在6位到12位之间
[Column("UserCode", "账号", 6, 12, ValidType.Length, false)]
public string UserCode { get; set; }

// 年龄,验证类型:不能为空,并且在15岁到80岁之间
[Column("Age", "年龄", 15, 80, ValidType.Value, false)]
public int Age { get; set; }
}
调用方法:
TestEo eo = new TestEo();
...
CheckEo.SaveOrUpdateEoCheck(eo);
如果验证过程发生相对应的值不满足配置条件,则会抛出CheckInputException异常
对于ORM,关键的一点在于多表之间的关联关系。祥亿平台支持一对一、一对多、多对多的关系管理,并支持自定义SQL查询扩展,以及延迟加载等功能。
祥亿平台称这些关联为外来属性,表示这些属性并不是本事实体拥有的,而是从其他实体引进来的。
首先,我们以销售实体、销售单实体来看如何配置外来属性
 
    /// <summary>
/// 销售实体
/// </summary>
[Table("SALE")]
public class SaleEo : BaseEo
{
[Column("SALE_ID")]
public string SaleId { get; set; }

[Column("SALE_TIME")]
public DateTime SaleTime { get; set; }

[Column("SALE_ALL_PRICE")]
public decimal SaleAllPrice { get; set; }

// 这个自定义列特性有6个参数:(SQL: SELECT DTL_ID,MAIN_ID,GOODS_NAME,GOODS_PRICE FROM SALE_DTL WHERE MAIN_ID=SaleId)
// 1.外来属性对应的表名称,这边指的是销售明细表名称;
// 2.决定外来属性的外键列名,即销售明细表的MAIN_ID;
// 3.决定外来属性的外键列值,即销售表的SALE_ID值;
// 4.外来属性的结果列.由于外来属性有可能是实体或者基础数据类型,所以需要手动设置列名.此处为*,或者DTL_ID,MAIN_ID,GOODS_NAME,GOODS_PRICE
// 5.外来属性的类型,这边就是实体集合;
// 6.外来属性的应用类型,这边表示增删改查;
// 7.是否延迟加载.此项仅应用于加载的时候.
[ForeignColumn("SALE_DTL", "MAIN_ID", "SaleId", "*", ForeignResultType.EoList, ForeignApplyType.LSUD, false)]
public EoList<SaleDtlEo> Dtls { get; set; }
}

/// <summary>
/// 销售明细实体
/// </summary>
[Table("SALE_DTL")]
public class SaleDtlEo : BaseEo
{
[Column("DTL_ID")]
public string DtlId { get; set; }

/// <summary>
/// 这个是对应销售实体的Id
/// </summary>
[Column("MAIN_ID")]
public string MainId { get; set; }

[Column("GOODS_NAME")]
public string GoodsName { get; set; }

[Column("GOODS_PRICE")]
public decimal GoodsPrice { get; set; }
}

配置好了之后,还需要在Sale的数据访问类里注册Dtls对应的数据访问:
/// <summary>
/// 销售数据访问
/// </summary>
public class SaleDao : BaseDao<SaleEo>
{
// 重写此方法,增加外来属性的数据访问实例.
protected override void RegisterForeignDao(Dictionary<string, BaseDao> foreignDao)
{
// Dtls表示外来属性的属性名
foreignDao.Add("Dtls", new SaleDtlDao() { Db = this.Db });
}
}

或者,也可以直接调用BaseDao<SaleEo>.RegisterForeignDao("Dtls", new SaleDtlDao() { Db = this.Db })方法。

只不过第二种方法,如果有多个外来属性的话,会调用多次,因为每次只能注册一个外来属性。

这样就可以实现外来属性的加载(普通加载、延迟加载)、保存、更新、删除。
 
接下来,我们来看下自定义sql的配置(举刚才的销售明细实体为例,假如我们要取得销售的时间,则可以通过以下配置):
/// <summary>
/// 销售明细实体
/// </summary>
[Table("SALE_DTL")]
public class SaleDtlEo : BaseEo
{
[Column("DTL_ID")]
public string DtlId { get; set; }

/// <summary>
/// 这个是对应销售实体的Id
/// </summary>
[Column("MAIN_ID")]
public string MainId { get; set; }

[Column("GOODS_NAME")]
public string GoodsName { get; set; }

[Column("GOODS_PRICE")]
public decimal GoodsPrice { get; set; }

/// <summary>
/// 这个属性,表示在加载销售明细的时候,也加载销售单的销售时间
/// </summary>
[ForeignColumn("SALE_TIME")]
public DateTime SaleTime { get; set; }
}
那么,使用的时候这样写就可以了:
BaseDao<SaleDtlEo> dao = new BaseDao<SaleDtlEo>();
// 在加载销售明细实体的时候,sql语句包含SaleTime的列即可
SaleDtlEo eo = dao.Load("select dtl.*,s.SALE_TIME from SALE_DTL as dtl,SALE as s where dtl.ID='xxx'");
 
如果有什么地方不懂的,或者有疑问的,可以加入群222515272讨论,希望大家给力!谢谢!
 
                                                  祥亿软件,版权所有。
 
 

抱歉!评论已关闭.