今天要说的实体框架并不是 ADO.NET EntityFramework,而是利用特性与反射技术自己来搭建一个简单的实体框架。在来讲之前先说些题外话,我们知道要想使一个项目有更好的健壮性、可移植型,是要将项目分层,不管是c/s,还是b/s框架一般都是三层架构,数据处理层(DAL)、业务逻辑层(BLL)、界面显示层(USL或者UI)。当然根据项目的业务流程可能分个七八层也是常有的事。今天主要讲的是在数据处理层是怎样实现实体架构的。

   言归正传,现在开始构建框架,首先建立数据库,就做一个学生选课信息系统(StudentManage),包括三张表,一个学生信息表(Students),一个课程表(CourseS),一个选课表(SCs),它们之间的关系如下图所示:

 

好了,数据库建好后,我们到程序中去进行操作,新建一个winform项目

看一下需要创建的类:

 

先来构建特性类

  /// <summary>

    /// 表特性类

    /// </summary>

    [AttributeUsage(AttributeTargets.Class)]//可以对类应用特性

    public class TableAttribute:Attribute

    {

        /// <summary>

        /// 表名

        /// </summary>

        public string TableName

        {

            get;

            set;

        }

    }

    [AttributeUsage(AttributeTargets.Property)]//可以对属性应用特性

    public class FieldAttribute : Attribute

    {

        /// <summary>

        /// 字段名

        /// </summary>

        public string FieldName

        {

            get;

            set;

        }

        /// <summary>

        /// 字段类型

        /// </summary>

        public SqlDbType FieldType

        {

            get;

            set;

        }

        /// <summary>

        /// 是不是主键

        /// </summary>

        public bool IsPrimaryKey

        {

            get;

            set;

        }

        /// <summary>

        /// 是否为空

        /// </summary>

        public bool IsNull

        {

            get;

            set;

        }

        /// <summary>

        /// 是否是自动增长

        /// </summary>

        public bool IsIdentity

        {

            get;

            set;

        }

    }

在构建实体类(和表是对应着的):

  /// <summary>

    /// 空接口,实体类的父类

    /// </summary>

    public class IEntity

    {

}

//学生类

 [Table(TableName = "Students")]//表名(注意TableAttribute可以简写为Table)

    public class Student:IEntity

    {

        [Field(FieldName="StudentID",FieldType=SqlDbType.NVarChar,IsPrimaryKey=true)]//字段特性

        public string StudentID

        {

            get;

            set;

        }

        [Field(FieldName="StudentName",FieldType=SqlDbType.NVarChar)]

        public string StudentName

        {

            get;

            set;

        }

        [Field(FieldName="Sex",FieldType=SqlDbType.NVarChar)]

        public string Sex

        {

            get;

            set;

        }

        [Field(FieldName="Age",FieldType=SqlDbType.TinyInt)]

        public int Age

        {

            get;

            set;

        }

     //课程类

    [Table(TableName="Courses")]

    public class Course:IEntity

    {

        [Field(FieldName="CourseID",FieldType=SqlDbType.Int,IsPrimaryKey=true,IsIdentity=true)]

        public int CourseID

        {

            get;

            set;

        }

        [Field(FieldName = "CourseName", FieldType = SqlDbType.NVarChar)]

        public string CourseName

        {

            get;

            set;

        }

}

//选课实体类

 [Table(TableName="SCs")]

    public class SC:IEntity

    {

        [Field(FieldName="StudentID",FieldType=SqlDbType.NVarChar,IsPrimaryKey=true)]

        public string StudentID

        {

            get;

            set;

        }

        [Field(FieldName = "CourseID", FieldType = SqlDbType.Int, IsPrimaryKey = true)]

        public int CourseID

        {

            get;

            set;

        }

    }

好了,实体类构建完成后,我们就来构建实体操作类:

 public class EntityOPT

    {

        string constr;//连接字符串

        SqlConnection con;//数据库连接

        /// <summary>

        /// 数据初始化

        /// </summary>

        public EntityOPT()

        {

            constr = "server=.;database=StudentManage;uid=sa;pwd=sa"; ;

            con = new SqlConnection(constr);

        }

        /// <summary>

        /// 获得表名

        /// </summary>

        /// <param name="type"></param>

        /// <returns></returns>

        string GetTableName(Type type)

        {

            return ((TableAttribute)type.GetCustomAttributes(true)[0]).TableName;//给类只加了一个自定义特性

        }

        public List<T> QueryAll<T>() where T : IEntity//由于不知道前台会传哪个实体类,所以用泛型

        {

            try

            {

                Type type = typeof(T);//得到类型

                List<T> entitys = new List<T>();//实体集合

                string sql = "select *from " + GetTableName(type);//获得表名,拼接sql语句

                SqlDataAdapter da = new SqlDataAdapter(sql, constr);

                DataTable dt = new DataTable();

                da.Fill(dt);//向DataTable中填充数据

                foreach (DataRow row in dt.Rows)//遍历所有行

                {

                    ConstructorInfo conInfo = type.GetConstructor(new Type[0]);//得到构造函数

                    object obj = conInfo.Invoke(null);//实例化对象

                    foreach (PropertyInfo pi in type.GetProperties())//得到所有属性

                    {

                        foreach (object ob in pi.GetCustomAttributes(true))//遍历字段所有特性

                        {

                            if (ob is FieldAttribute)

                            {

                                string fieldname = (ob as FieldAttribute).FieldName;//得到表中字段的名字

                                pi.SetValue(obj, row[fieldname], null);//给实体类属性赋值

                                break;

                            }

                        }

                    }

                    entitys.Add((T)obj);

                }

                return entitys;

            }

            catch (Exception ex)

            {

                throw new Exception("数据层查询所有数据发生异常:" + ex.Message);

            }

        }

        /// <summary>

        /// 插入数据

        /// </summary>

        /// <param name="entity"></param>

        /// <returns></returns>

        public bool InsertEntity(IEntity entity)

        {

            try

            {

                Type type = entity.GetType();

                List<SqlParameter> pars = new List<SqlParameter>();//sql参数集合

                string sql = "insert into " + GetTableName(type) + " values(";

                foreach (PropertyInfo pi in type.GetProperties())//遍历类的所有属性

                {

                    foreach (object obj in pi.GetCustomAttributes(true))//遍历属性的特性

                    {

 

                        if (obj is FieldAttribute && !(obj as FieldAttribute).IsIdentity)//有些主键是不自动增长的,如学号

                        {

                            string par = "@" + (obj as FieldAttribute).FieldName;

                            sql += par + ",";//拼接sql语句

                            SqlParameter sp = new SqlParameter(par, (obj as FieldAttribute).FieldType);

                            sp.Value = pi.GetValue(entity, null);

                            pars.Add(sp);

                            break;

                        }

                    }

                }

                sql = sql.TrimEnd(',') + ")";//去掉多余的逗号

                return SaveChange(sql, pars);

            }

            catch (Exception ex)

            {

                throw new Exception(ex.Message);

            }

        }

        /// <summary>

        /// 删除数据

        /// </summary>

        /// <param name="entity"></param>

        /// <returns></returns>

        public bool DeleteEntity(IEntity entity)

        {

            try

            {

                Type type = entity.GetType();

                List<SqlParameter> sps = new List<SqlParameter>();

                string sql = "delete " + GetTableName(type) + " where ";

                foreach (PropertyInfo pi in type.GetProperties())

                {

                    foreach (object obj in pi.GetCustomAttributes(true))

                    {

                        if (obj is FieldAttribute && (obj as FieldAttribute).IsPrimaryKey)

                        {

                            FieldAttribute fa = obj as FieldAttribute;

                            sql += fa.FieldName + "=@" + fa.FieldName+" and ";//可能会是联合主键

                            SqlParameter sp = new SqlParameter("@" + fa.FieldName, fa.FieldType);

                            sp.Value = pi.GetValue(entity, null);

                            sps.Add(sp);

                            break;

                        }

                    }

                }

                sql = sql.Substring(0, sql.Length - 4);

                return SaveChange(sql,sps);

            }

            catch (Exception ex)

            {

                throw new Exception(ex.Message);

            }

        }

        /// <summary>

        /// 更新数据

        /// </summary>

        /// <param name="entity"></param>

        /// <returns></returns>

        public bool UpdateEntity(IEntity entity)

        {

            try

            {

                Type type = entity.GetType();

                List<SqlParameter> pars = new List<SqlParameter>();

                string sql = "update " + GetTableName(type) + " set ";

                string where = " where ";

                foreach (PropertyInfo pi in type.GetProperties())

                {

                    foreach (object obj in pi.GetCustomAttributes(true))

                    {

                        if (obj is FieldAttribute)

                        {

                            FieldAttribute fa = obj as FieldAttribute;

                            if (fa.IsPrimaryKey)

                            {

 

                                where +=  fa.FieldName + "=@" + fa.FieldName;

                                SqlParameter sp = new SqlParameter("@" + fa.FieldName, fa.FieldType);

                                sp.Value = pi.GetValue(entity, null);

                                pars.Add(sp);

                            }

                            else

                            {

                                sql += fa.FieldName + "=@" + fa.FieldName + ",";

                                SqlParameter sp = new SqlParameter("@" + fa.FieldName, fa.FieldType);

                                sp.Value = pi.GetValue(entity, null);

                                pars.Add(sp);

                            }

                            break;

                        }

                    }

                }

                sql = sql.TrimEnd(',') + where;

                return SaveChange(sql, pars);

            }

            catch (Exception ex)

            {

                throw new Exception(ex.Message);

            }

        }

        /// <summary>

        /// 向数据库提交数据

        /// </summary>

        /// <param name="sql"></param>

        /// <param name="pars"></param>

        /// <returns></returns>

        bool SaveChange(string sql, List<SqlParameter> pars)

        {

            try

            {

                SqlCommand cmd = new SqlCommand(sql, con);

                foreach (SqlParameter par in pars)

                {

                    cmd.Parameters.Add(par);

                }

                con.Open();

                int count = cmd.ExecuteNonQuery();

                if (count > 0)

                {

                    return true;

                }

                else

                {

                    return false;

                }

            }

            catch (Exception ex)

            {

 

                throw new Exception(ex.Message);

            }

            finally

            {

                con.Close();

            }

        }

 

    }

好了,到这一步,一个简单的实体框架算是构建完成,下面来测试。

先做一个界面:

 

四个button控件,一个dataGridView控件。

先来做学生的添加:

            Student student = new Student();

            student.StudentID = "09040401036";

            student.StudentName = "张三";

            student.Age = 18;

            student.Sex = "男";

            if (entityopt.InsertEntity(student))

            {

                MessageBox.Show("添加成功!");

            }

            else

            {

                MessageBox.Show("添加失败!");

            }

     查询操作:

        private void button4_Click(object sender, EventArgs e)

        {

            dataGridView1.DataSource = entityopt.QueryAll<Student>();

        }

单击添加并查询:

 

添加成功。

来做修改,把名字改为李四:

     Student student = new Student();

            student.StudentID = "09040401036";

            student.StudentName = "李四";

            student.Age = 18;

            student.Sex = "男";

            if (entityopt.UpdateEntity(student))

            {

                MessageBox.Show("修改成功!");

            }

            else

            {

                MessageBox.Show("修改失败!");

            }

单击修改,并查询:

 

修改成功。

删除刚才的学生信息:

     Student student = new Student();

            student.StudentID = "09040401036";

            if (entityopt.DeleteEntity(student))

            {

                MessageBox.Show("删除成功!");

            }

            else

            {

                MessageBox.Show("删除失败!");

            }

     删除并查询:

 

删除成功。

下面在对课程操作,首先添加课程:

     Course course = new Course();

            course.CourseName = "C#";

            if (entityopt.InsertEntity(course))

            {

                MessageBox.Show("添加成功!");

            }

            else

            {

                MessageBox.Show("添加失败!");

            }

查询操作:

dataGridView1.DataSource = entityopt.QueryAll<Course>();

点击添加,然后查询,结果:

 

我们看到课程也添加成功了,在做修改:

     Course course = new Course();

            course.CourseID = 1;

            course.CourseName = "asp.net";

            if (entityopt.UpdateEntity(course))

            {

                MessageBox.Show("修改成功!");

            }

            else

            {

                MessageBox.Show("修改失败!");

            }

点击修改,并查询,结果:

 

课程也能修改成功!

再来删除!

     Course course = new Course();

            course.CourseID = 1;

            if (entityopt.DeleteEntity(course))

            {

                MessageBox.Show("删除成功!");

            }

            else

            {

                MessageBox.Show("删除失败!");

            }

   看一下运行结果:

  

   删除成功!

好了,到这一步我们发现实体框架构建成功,并能运行。不过注意了,如果要是做选课的修改时,不能直接调用修改方法,因为它是联合主键,应该先删除在添加,其实修改本本身就是先删除后添加的过程。

好,今天讲的东西虽然是简单实体框架,但也有难度,一般大公司都有自己的实体框架,有不懂的地方可以和我交流。

作者: 森罗万象 发表于 2011-06-11 19:45 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架