• .NET框架下ORM的一个轻量高效替代方案


    从最初做JAVA开发到现在致力于.NET平台,经手的大大小小的项目也不在少数。刚开始每写成一个程序还能获得不少的成就感,但随着开发年限的增加、项目代码行的增加,写代码更多时候变成一种糊口的工具而非兴趣时,越来越被大量相似的SQL搅得头晕脑胀,尤其维护旧程序时,对SQL的调试更是让人头大。于是,一直致力于找出一个方法,可以不用每次都去编写那些烦人的SQL。

    答案是肯定的,JAVA平台下有个Hibernate的ORM框架,它应该是最早的一个成熟的ORM软件,貌似可以解决我的问题。迫不及待的下载、使用MyEclipse去写测试程序,却发现并不如想象中的好,对我来说,最大的障碍在于那个XML配置文件。借助于IDE,配置工作或许还不是太繁琐,但脱离IDE之后,我发现对这个配置文件维护的困难绝对不在直接维护SQL命令之下。当然,好处还是有的,比如不用去调试每一条SQL。

    虽然不太情愿,但毕竟脱离IDE的情况还是很少,所以也就“爱用不用”地用了一段时间。

    之后,机缘巧合的转向.NET平台,从.NET Framework 1.1和VS2003开始,到现在的.NET Framework 2.0和VS2005,随着在.NET平台开发经验的日渐丰富,对C#特性越来越全面的了解,终于决定要自己写一个更加符合C#口味的ORM框架,完全的面向对象,更加简洁,更加高效,对IDE的智能感知支持更好(早期绑定) 。

    一起来看看它的工作方式。

    假设有一个员工表,字段为 id,employee_id,name,department_id
    有一个实体类EmployeeInfo与上表各字段对应
    现在我们需要为这个表写一个访问类,提供对数据库的增、删、改、查工作。
    下面是实现以上功能的所有代码:

    public class EmployeeTable : TableAccess<EmployeeInfo> {

            
    internal override ColumnParameter[] FillColumnParameters(EmployeeInfo entity) {
                
    return base.BuildColumnParameter(
                    entity.ID,
                    entity.EmployeeID,
                    entity.Name,
                    entity.DepartmentID
                );
            }

            
    public override string TableName {
                
    get { return "employee_table"; }
            }

            
    public override TableColumnCollection TableColumns {
                
    get {
                    TableColumnCollection list 
    = new TableColumnCollection(4);
                    list.AddRange(
    new TableColumn[] { 
                        
    new TableColumn("id"true), // 自增只读字段 
                        new TableColumn("employee_id"),
                        
    new TableColumn("name"),
                        
    new TableColumn("department_id")
                    });
                    
    return list;
                }
            }

            
    internal override EmployeeInfo BuildEntity(MySqlDataReader reader, int startIndex) {
                EmployeeInfo info 
    = new EmployeeInfo();
                info.ID 
    = reader.GetInt32(0);
                info.EmployeeID 
    = reader.GetString(1);
                info.Name 
    = reader.GetString(2);
                info.DepartmentID 
    = DataReadyUtility.GetInt32(reader,3);
                
    return info;
            }


    }


    从上面的代码可以看出,对一个独立表的访问,只需重写抽象基类的4个方法即可,可实现以下功能:

    • 按主键获取一个数据行 GetByPrimaryKey(object)
    • 获取数据表的所有记录 GetAll()
    • 查询 Search(SearchConditionCollection, ...)
    • 分页查询 Search(SearchConditionCollection, int, int, ...)
    • 保存 Save(EmployeeInfo)
    • 按主键值修改 Modify(...)
    • 按条件修改 Modify(SearchConditionCollection, ...)
    • 按主键删除 Delete(...)
    • 按查询条件删除 Delete(SearchConditionCollection, ...)

    下面的代码是对EmployeeTable类的扩充,使它具有足够多的功能:

    public class EmployeeTable : TableAccess<EmployeeInfo> {

        
    // 修改员工名字
        public int ChangeName(int id, string name) {
            EmployeeInfo info 
    = new EmployeeInfo();
            info.Name 
    = name;
            
    // 使用ModifyBounds.None表示仅修改后面指定的字段 TableColumns["name"]
            return base.Modify(id, info, ModifyBounds.None, TableColumns["name"]);
        }
        
        
    // 按名字获取员工,不分页 
        public IList<EmployeeInfo> GetByName(string name) {
            SearchConditionCollection filter 
    = new SearchCoditionCollection();
            
    // 按Like查询name字段
            filter.add(new SearchCondition("name"new ColumnComparison(SqlOperator.Like, name)));
            
    return base.Search(filter);
        }
        
        
    // 按名字获取员工,并分页 。输出不分页情况下的记录总数,供前台分页使用
        public IList<EmployeeInfo> GetByName(string name, int pageSize, int pageIndex, out int itemCount) {
            SearchConditionCollection filter 
    = new SearchCoditionCollection();
            
    // 按Like查询name字段
            filter.add(new SearchCondition("name"new ColumnComparison(SqlOperator.Like, name)));
            
    return base.Search(filter, pageSize, pageIndex, out itemCount);
        }

    }

    最后就是对上面类各个方法的调用了,以实现项目的需求。

    public class EmployeeTableTest {

        
    void Test() {
        
            EmployeeTable employeeDAL 
    = new EmployeeTable();
            SearchConditionCollection filter 
    = new SearchConditionCollection(); // 查询条件生成器
            
            
    // 保存一个员工
            EmployeeInfo employee = new EmployeeInfo();
            employee.Name 
    = "wfyfngu";
            employee.DepartmentID 
    = 4;
            employeeDAL.Save(employee);
        
            
    // 获取ID为1的员工
            EmployeeInfo info = employeeDAL.GetByPrimaryKey(1);
            
            
    // 查询所有员工
            IList<EmployeeInfo> all = employeeDAL.GetAll();
            
            
    // 分页查询
            int itemCount;
            IList
    <EmployeeInfo> pagedSource = employeeDAL.Search(null,10,1,out itemCount);
            
            
    // 修改ID为1的员工的名字
            employeeDAL.ChangeName(1"wfyfngu");
            
            
    // 考虑到项目分层,业务逻辑层应该对数据库字段一无所知
            
    // 所以,下面演示的方法仅仅出于演示目的,将字段名硬编码到方法中
            
            
    // 删除ID为 1 2 5 7 的用户
            filter.Add(new SearchCondition(
                
    "user_id",
                
    new ColumnComparison(SqlOperator.In, 1,2,5,7)
            ));
            employeeDAL.Delete(filter);
            
            
    // 查询名字以wfy开头的员工,并分页
            filter.Clear();
            filter.Add(
    new SearchCondition(
                
    "name",
                
    new ColumnComparison(SqlOperator.StartWith, "wfy")
            ));
            IList
    <EmployeeInfo> result = employeeDAL.Search(filter,10,1,out itemCount);
            
            
        }

    }


    其它功能,如简单的联表查询,视图查询等不一一列举。

    附件说明:附件为本人编写的ORM替代框架,针对MySql编写,由于Cache功能涉及到另一个类库,所以在附件中去除了,需要的可以自己加入。

    几个主要类源码:

    ReadonlyTableAccess<T>

    TableAccess<T>

    JoinTableAccess<T>

    框架下载地址:https://files.cnblogs.com/wfyfngu/SqlUtility.zip

  • 相关阅读:
    Git命令家底儿及Git数据通信原理详解
    git SSH keys
    TRIM函数
    c# List AddRange
    vtk第一个程序
    MFC CStatic类动态创建
    前端基础之BOM和DOM
    JavaScript
    前端CSS属性相关
    前端CSS
  • 原文地址:https://www.cnblogs.com/wfyfngu/p/1657762.html
Copyright © 2020-2023  润新知