欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C# 轻量级系统基础架构 (MVP MEF + EF6)

程序员文章站 2022-04-08 19:53:03
0 综述 1 MVP各模块规范 1.1 实体模块规范 1.1.1 命名规范 实体类封装到单独的DLL中,DLL命名遵循.DataEntity。数据库实体类名遵循:数据库表名去掉复数后缀,如“s”、“es”等(数据库表的名称必须是名词复数)。 1.1.2 架构规范 实体模块中 ......

 

0 综述

 

1 mvp各模块规范

 

1.1 实体模块规范

1.1.1 命名规范

    实体类封装到单独的dll中,dll命名遵循<projectname>.dataentity。数据库实体类名遵循:数据库表名去掉复数后缀,如“s”、“es”等(数据库表的名称必须是名词复数)。

1.1.2 架构规范

    实体模块中必须包含一个泛型实体接口,供所有数据实体类实现该接口,该接口所继承接口亦为各实体类所统一实现(例如该接口实现自iequatable<t>),该接口泛型参数必须为本接口类型,该接口可以不声明任何成员。例如:

1 namespace testproj.dataentity
2 {
3     public interface itestprojentity<t> : iequatable<t>
4         where t : itestprojentity<t>
5     {
6     }
7 }

    该接口用于规范实体类编写。

    该接口命名规范遵循:i+<项目名>+entity形式,该接口必须为泛型接口,该接口泛型参数必须是本接口。实体类只映射数据库实际结构,实体类之间主外键关联用程序逻辑维护,即:不采用实体间依赖的方式表示主外键关联(实体类不包含其他实体类的实例对象、列表、集合等)。注意:实体类所有值类型(例如 int、bool、long)必须指定为可为空类型(即诸如int?, bool?, long?),这样便于通过反射,将实体类生成查询sql语句,即所有为空字段不生成条件。

    实体类示例代码如下:

public class patient : iopentcmentity<patient>
{
    public string id { get; set; }   //主键id
    public string name { get; set; } //姓名

    public bool equals(patient other)
    {
        if (other == null)
        {
            return false;
        }
        if (other == this)
        {
            return true;
        }
        bool res =
            other.id == id &&
            other.name == name;
        return res;
    }
}

 

1.2 数据库访问接口

1.2.1 命名规范

    数据库访问接口必须封装到单独的dll中,dll命名遵循 i + <projectname>.dataoperate。数据库访问类命名遵循:i + <相对应实体类命名> + “dao”。

1.2.2 架构规范

    数据库访问接口必须包含一个泛型接口,该泛型接口用于统一声明所有公共的数据库acid函数,该接口泛型参数必须是数据库实体类所共同实现的接口类型,该接口命名必须为ibasedao。示例代码如下:

 1 public interface ibasedao<e>
 2     where e : iopentcmentity<e>
 3 {
 4     /// <summary>
 5     /// 是否存在id所对应的记录
 6     /// </summary>
 7     /// <param name="id"></param>
 8     /// <returns></returns>
 9     bool exists(string id);
10     /// <summary>
11     /// 是否存在参数对象所描述的记录(属性为空表示该属性不作为查询条件)
12     /// </summary>
13     /// <param name="condition"></param>
14     /// <returns></returns>
15     bool exists(e condition);
16     /// <summary>
17     /// 将参数描述的实体对象添加到数据库中
18     /// </summary>
19     /// <param name="po"></param>
20     /// <returns></returns>
21     bool addentity(e po);
22     /// <summary>
23     /// 将参数描述的实体对象集合添加到数据库中
24     /// </summary>
25     /// <param name="pos"></param>
26     /// <returns></returns>
27     bool addentity(list<e> pos);
28     /// <summary>
29     /// 根据id从数据库中删除实体
30     /// </summary>
31     /// <param name="id"></param>
32     /// <returns></returns>
33     bool delentity(string id);
34     /// <summary>
35     /// 依据参数描述的数据库记录更新数据库,
36     /// 本操作需要先从数据库获取具体的对象。
37     /// </summary>
38     /// <param name="po"></param>
39     /// <returns></returns>
40     bool updateentity(e po);
41     /// <summary>
42     /// 依据参数描述的对象为条件,获取记录数。
43     /// </summary>
44     /// <param name="condition"></param>
45     /// <returns></returns>
46     long getcount(e condition);
47     /// <summary>
48     /// 获取总记录数
49     /// </summary>
50     /// <returns></returns>
51     long getcount();
52     /// <summary>
53     /// 获取所有实体对象集合
54     /// </summary>
55     /// <returns></returns>
56     list<e> selectentity();
57     /// <summary>
58     /// 获取分页对象集合
59     /// </summary>
60     /// <param name="beg"></param>
61     /// <param name="len"></param>
62     /// <returns></returns>
63     list<e> selectentity(int beg, int len);
64     /// <summary>
65     /// 根据id获取一个实体对象
66     /// </summary>
67     /// <param name="id"></param>
68     /// <returns></returns>
69     e selectentity(string id);
70     /// <summary>
71     /// 依据条件获取实体集合
72     /// </summary>
73     /// <param name="condition"></param>
74     /// <returns></returns>
75     list<e> selectentity(e condition);
76 }

     针对每个数据库表创建对应的数据访问接口,该接口继承自ibasedao,泛型参数为该数据表对应的实体类。代码示例如下:

1 public interface itestdao:ibasedao<test>
2 {
3 }

1.3 数据业务接口规范

1.3.1 命名规范

    业务接口必须封装到单独的dll中,dll命名遵循<projectname>.databiz。业务类命名遵循:相对应实体类+"bo"。

1.3.2 架构规范

    数据库业务接口必须包含一个公用的泛型接口,该泛型接口用于统一声明所有公共的数据库acid函数,该接口泛型参数必须是数据库实体类所共同实现的接口类型,和一个用于访问数据库的ibasedao类型属性。示例代码如下:

 1 public interface ibasebo<e, dao>
 2     where e : iopentcmentity<e>
 3     where dao : ibasedao<e>
 4 {
 5     /// <summary>
 6     /// 数据库操作对象
 7     /// </summary>
 8     dao dboperator { get; set; }
 9     /// <summary>
10     /// 是否存在id所对饮的记录
11     /// </summary>
12     /// <param name="id"></param>
13     /// <returns></returns>
14     bool exists(string id);
15     /// <summary>
16     /// 是否存在参数对象所描述的记录(属性为空表示该属性不作为查询条件)
17     /// </summary>
18     /// <param name="condition"></param>
19     /// <returns></returns>
20     bool exists(e condition);
21     /// <summary>
22     /// 将参数描述的实体对象添加到数据库中
23     /// </summary>
24     /// <param name="po"></param>
25     /// <returns></returns>
26     bool addentity(e po);
27     /// <summary>
28     /// 将参数描述的实体对象集合添加到数据库中
29     /// </summary>
30     /// <param name="pos"></param>
31     /// <returns></returns>
32     bool addentity(list<e> pos);
33     /// <summary>
34     /// 根据id从数据库中删除实体
35     /// </summary>
36     /// <param name="id"></param>
37     /// <returns></returns>
38     bool delentity(string id);
39     /// <summary>
40     /// 依据参数描述的数据库记录更新数据库,
41     /// 本操作需要先从数据库获取具体的对象。
42     /// </summary>
43     /// <param name="po"></param>
44     /// <returns></returns>
45     bool updateentity(e po);
46     /// <summary>
47     /// 依据参数描述的对象为条件,获取记录数。
48     /// </summary>
49     /// <param name="condition"></param>
50     /// <returns></returns>
51     long getcount(e condition);
52     /// <summary>
53     /// 获取总记录数
54     /// </summary>
55     /// <returns></returns>
56     long getcount();
57     /// <summary>
58     /// 获取所有实体对象集合
59     /// </summary>
60     /// <returns></returns>
61     list<e> selectentity();
62     /// <summary>
63     /// 获取分页对象集合
64     /// </summary>
65     /// <param name="beg"></param>
66     /// <param name="len"></param>
67     /// <returns></returns>
68     list<e> selectentity(int beg, int len);
69     /// <summary>
70     /// 根据id获取一个实体对象
71     /// </summary>
72     /// <param name="id"></param>
73     /// <returns></returns>
74     e selectentity(string id);
75     /// <summary>
76     /// 依据条件获取实体集合
77     /// </summary>
78     /// <param name="condition"></param>
79     /// <returns></returns>
80     list<e> selectentity(e condition);
81 }

    针对每个数据库表创建对应的数据访问接口,该接口继承自ibasedao,泛型参数为该数据表对应的实体类。代码示例如下:

public interface isymptombo : ibasebo<pathology, isymptomdao>
{
    //todo:type your specific business logical code
}

    该接口中可以声明特定与该数据表的特定业务函数、属性。

1.4 数据访问模块

1.4.1 命名规范

    数据访问模块必须封装为单独的dll,dll文件命名规范遵循<项目名>.dataoperate,数据访问类遵循 <表名单数形式> + dao 的命名规范。

1.4.2 架构规范

    数据访问模块需要引用system.componentmodel.composition命名空间。数据访问模块若使用ef6,则必须包含一个数据上下文类,该类命名个规范为<project>context,该类用于提供entityframework6的数据上下文。    

 数据上下文类结构如下:

public class opentcmcontext : dbcontext
{
    public opentcmcontext()
        : base("testconnstr")
    {
    }
    public dbset<testtablea> testtableacontext { get; set; }
    public dbset<testtablea> testtablebcontext { get; set; }
}

    数据访问类之间不互相依赖,每个数据访问类实现自按数据库表对应的数据访问接口,并具备一个私有只读的数据上下文对象。数据访问类每个实现自ibasedao的函数不互相引用。

    数据访问类若使用ef6的形式,就需要辩证的看待数据库增删改查的方式,某些简单的数据库操作若使用纯ef6方式,数据库交互数量级有按指数翻倍的可能。本文建议的数据库访问方式,尽量采用sql,不涉及大量重复操作数据库的情况下,兼顾ef6的便捷操作。数据访问类需要向mef容器导出其自身,鉴于每个数据访问接口皆对应一个单独的实现类,这里采用[export(typeof(<父接口>))]的方式。

  数据访问类部分代码示意如下:

[export(typeof(itestdao))]
public class testdao : itestdao
{
    public testdao()
    {
        context = new opentcmcontext();
    }
    private readonly testprojcontext context;
    public bool exists(string id)
    {
        var res = context.testcontext.sqlquery("id='{0}'", id);
        if (res.firstordefault() == null)
        {
            return false;
        }
        int count = res.count();
        return count > 0;
    }
        //...
}

1.5 数据库业务模块

1.5.1 命名规范

    数据库业务模块必须封装为单独的dll,dll文件命名规范为<项目名>.databiz,数据库业务类命名遵循<对应实体类名> + bo。

1.5.2 架构规范

    数据库业务类实现自其对应的业务接口,其必须实现接口规定的数据库操作抽象接口对象属性,并标注从mef容器注入该对象实例。并在构造函数中显式构建该接口对象。该类也需要向mef容器导出其自身,供*业务构建其示例。数据库业务类参考代码示例如下:

[export("testbo", typeof(itestbo))]
public class testbo : itestbo
{
    public testbo()
    {
        var catalog = new directorycatalog("./");
        var container = new compositioncontainer(catalog);
        container.composeparts(this);
    }
    [import]
    public itestdao dboperator { get; set; }

    public bool exists(string id)
    {
        return dboperator.exists(id);
    }
        //...
}

2 总结

 至此,一个基于.net + mef + ef6 的轻量级系统基础架构就完成了。其中业务接口依赖于数据操作接口,业务模块与数据操作模块分别依赖于其所对应接口,具体模块之间没有依赖关系。各接口、具体模块均需添加实体模块的引用。

 

C# 轻量级系统基础架构 (MVP MEF + EF6)

C# 轻量级系统基础架构 (MVP MEF + EF6)