这仅仅是一个新手写给新手共同入门的博文!这是一个使用MVC,和一些主流框架(Autofac,Log4Net等)来完成的一个简单的项目。和各位学习MVC的朋友们一起学习。
如左图所示,先建好文件夹,然后再来填充内容。
一:Zero,MVC4.0项目
二:Domain: Abstract仓储类接口,Concrete仓储类实现,Entities实体模型
三:Infrastructure:基础设施
四:IOC:主要用于解耦仓储类接口
首先,从最底层写起:
第一步,写一个操作数据库的类
我这边采用的是底层使用ADO.NET,通过泛型约束和反射来实现一个简单的ORM
1:先在Conntion里面放一个SQLHelper类(找个自己熟悉的),这里就不做工厂了。怎么简单怎么来,先让东西跑起来
2:写个属于自己的ORM类:我们先来想想,如果不考虑存储过程(返回集合,直接LINQ处理数据),我们需要什么东西来拼接SQL语句,首先,要有表名,然后主键,然后各个字段名称,其他的先不考虑,现在写一个IDateBase抽象类来约束实体类,往Infrastructure层的IBase文件夹里新建一个IDateBase抽象类,代码如下:
namespace Zero.Infrastructure.IBase{ public abstract class IDataBase { public virtual string TableName { get; set; } public virtual int ID { get; set; } }}
这样就解决了表名和主键名称在用泛型的时候,取不到的问题了,但是字段名称不行啊,每个表的字段都不一样,所以最后还是要用到反射,写一个特性来反射,在Infrastructure层的Attributes文件夹下面建立一个类DataFieldAttribute
代码如下:
namespace Zero.Infrastructure.Attributes{ public class DataFieldAttribute : Attribute { PRivate string _FieldName; public DataFieldAttribute(string fieldname) { this._FieldName = fieldname; } public string FieldName { get { return this._FieldName; } set { this._FieldName = value; } } }}
完事具备,我们先写一个实体类,然后开始写ORM
实体里建立在Domain的Entities文件夹下面,记得Domain层要引用Infrastructure层
using System;using System.Collections.Generic;using System.Linq;using System.Text;using Zero.Infrastructure.Attributes;using Zero.Infrastructure.IBase;namespace Zero.Domain.Entities{ public class User: IDataBase { public User() { TableName = "User"; } private string _TableName; public override string TableName { get { if (_TableName == null) { return "User"; } else { return _TableName; } } set { _TableName = value; } } public override int ID { get; set; } [DataFieldAttribute("UserName")] public string UserName { get; set; } }}
代码如上
现在开始写自己的ORM类
在Infrastructure层的Conntion文件夹下面建立一个ZeroORM类,ORM需要实现的功能有:查询,添加,更改,删除,4个基本功能
public class ZeroORMwhere<T> where T : IBase.IDataBase{ public string SqlConnctionString { get; set; } public SqlConnection conn { get; set; } public SqlTransaction tran { get; set; }}
然后增加查询方法:
/// <summary> /// 获得实体T所有数据 /// </summary> /// <returns></returns> public List<T> Select(T t) { List<T> list = new List<T>(); string sql = "select * from " + t.TableName + " WITH (NOLOCK) order by id desc"; DataSet ds = SqlHelper.ExecuteDataset(SqlConnctionString, CommandType.Text, sql); for (int i = 0; i < ds.Tables[0].Rows.Count; i++) { list.Add(DataSetToEntity.DsToEntity<T>(ds, i)); } return list; }
DataSetToEntity这个类就是网上找的Dataset转实体的方法,大家可以网上找下,最后返回一个List集合
然后是添加方法
/// <summary> /// 插入新数据 /// </summary> /// <param name="t">实体类</param> /// <returns></returns> public int Insert(T t) { try { Type mytype = t.GetType(); // 获取类的所有公共属性 System.Reflection.PropertyInfo[] pInfo = mytype.GetProperties(); string FieldName = "";//字段名称 string Values = "";//值 StringBuilder sql = new StringBuilder(); List<SqlParameter> paras = new List<SqlParameter>();//不定参集合,防注入 sql.Append("Insert into "); sql.Append(mytype.Name);//数据库表名,可以放t.TableName sql.Append("("); object[] objDataFieldAttribute = null; foreach (System.Reflection.PropertyInfo pio in pInfo) { objDataFieldAttribute = pio.GetCustomAttributes(typeof(DataFieldAttribute), false); if (objDataFieldAttribute != null && objDataFieldAttribute.Length > 0) { FieldName += ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName + ",";//给字段赋值 Values += "@" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName + ",";//给对应字段的值赋值 paras.Add(new SqlParameter("@" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName, pio.GetValue(t, null)));//添加不定参 } } FieldName = FieldName.TrimEnd(','); Values = Values.TrimEnd(','); sql.Append(FieldName); sql.Append(") VAlUES ("); sql.Append(Values); sql.Append(")"); int i = SqlHelper.ExecuteNonQuery(SqlConnctionString, CommandType.Text, sql.ToString(), paras.ToArray()); return i; } catch (Exception) { return -1; throw; } }
还有修改和删除方法,以及带事务的方法,一起贴出来。
using System;using System.Collections.Generic;using System.Data;using System.Data.SqlClient;using System.Linq;using System.Reflection;using System.Text;using Zero.Infrastructure.Attributes;using Zero.Infrastructure.Utilities;namespace Zero.Infrastructure.Conntion{ public class ZeroORM<T> where T : IBase.IDataBase { public string SqlConnctionString { get; set; } public SqlConnection conn { get; set; } public SqlTransaction tran { get; set; } /// <summary> /// 获得实体T所有数据 /// </summary> /// <returns></returns> public List<T> Select(T t) { List<T> list = new List<T>(); string sql = "select * from [" + t.TableName + "] WITH (NOLOCK) order by id desc"; //出于性能考虑,不用反射来获取表名 DataSet ds = SqlHelper.ExecuteDataset(SqlConnctionString, CommandType.Text, sql); for (int i = 0; i < ds.Tables[0].Rows.Count; i++) { list.Add(DataSetToEntity.DsToEntity<T>(ds, i)); } return list; } /// <summary> /// 根据主键ID获取数据(一条) /// </summary> /// <param name="id"></param> /// <param name="TableName"></param> /// <returns></returns> public T SelectByID(int id, T t) { string sql = "select * from [" + t.TableName + "] WITH (NOLOCK) where ID=@ID"; //出于性能考虑,不用反射来获取表名 DataSet ds = SqlHelper.ExecuteDataset(SqlConnctionString, CommandType.Text, sql, new SqlParameter("@ID", id)); t = DataSetToEntity.DsToEntity<T>(ds, 0); PropertyInfo[] prop = t.GetType().GetProperties(); return t; } /// <summary> /// 插入新数据 /// </summary> /// <param name="t">实体类</param> /// <returns></returns> public int Insert(T t) { try { Type mytype = t.GetType(); // 获取类的所有公共属性 System.Reflection.PropertyInfo[] pInfo = mytype.GetProperties(); string FieldName = "";//字段名称 string Values = "";//值 StringBuilder sql = new StringBuilder(); List<SqlParameter> paras = new List<SqlParameter>(); sql.Append("Insert into ["); sql.Append(mytype.Name);//数据库表名 sql.Append("]("); object[] objDataFieldAttribute = null; foreach (System.Reflection.PropertyInfo pio in pInfo) { objDataFieldAttribute = pio.GetCustomAttributes(typeof(DataFieldAttribute), false); if (objDataFieldAttribute != null && objDataFieldAttribute.Length > 0) { FieldName += ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName + ","; Values += "@" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName + ","; paras.Add(new SqlParameter("@" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName, pio.GetValue(t, null))); } } FieldName = FieldName.TrimEnd(','); Values = Values.TrimEnd(','); sql.Append(FieldName); sql.Append(") VAlUES ("); sql.Append(Values); sql.Append(")"); int i = SqlHelper.ExecuteNonQuery(SqlConnctionString, CommandType.Text, sql.ToString(), paras.ToArray()); return i; } catch (Exception) { return -1; throw; } } /// <summary> /// 更新数据 /// </summary> /// <param name="t">需更新的实体类</param> /// <returns></returns> public int Update(T t) { try { int i = 0; int primarykey = t.ID; T oldT = t; Type mytype = t.GetType(); System.Reflection.PropertyInfo[] pInfo = mytype.GetProperties(); oldT = SelectByID(primarykey, oldT);//获得原始值,为日志做准备 if (t != oldT) { string SetValue = "";//字段名称 string Where = " where ID=@ID";//值 StringBuilder sql = new StringBuilder(); List<SqlParameter> paras = new List<SqlParameter>(); sql.Append("Update ["); sql.Append(mytype.Name); sql.Append("] Set "); object[] objDataFieldAttribute = null; foreach (System.Reflection.PropertyInfo pio in pInfo) { objDataFieldAttribute = pio.GetCustomAttributes(typeof(DataFieldAttribute), false); if (objDataFieldAttribute != null && objDataFieldAttribute.Length > 0 && pio.GetValue(t, null).ToString() != pio.GetValue(oldT, null).ToString()) { SetValue += ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName + "=" + "@" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName + ","; paras.Add(new SqlParameter("@" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName, pio.GetValue(t, null))); } } SetValue = SetValue.TrimEnd(','); sql.Append(SetValue); sql.Append(Where); paras.Add(new SqlParameter("@ID", primarykey)); i = SqlHelper.ExecuteNonQuery(SqlConnctionString, CommandType.Text, sql.ToString(), paras.ToArray()); return i; } else { return -2; } } catch (Exception) { return -1; throw; } } /// <summary> /// 删除数据 /// </summary> /// <param name="t"></param> /// <returns></returns> public int Delete(T t) { int i = 0; int primarykey = t.ID; Type mytype = t.GetType(); string TableName = mytype.Name; string Where = " where ID =@ID"; string sql = "DELETE FROM " + TableName + Where; try { i = SqlHelper.ExecuteNonQuery(SqlConnctionString, CommandType.Text, sql, new SqlParameter("@ID", primarykey)); return i; } catch (Exception) { return -1; throw; } } /// <summary> /// 开始事务 /// </summary> /// <returns></returns> public void BeginTran() { try { conn = new SqlConnection(SqlConnctionString); conn.Open(); tran = conn.BeginTransaction(); } catch (Exception) { tran.Rollback(); conn.Close(); throw; } } /// <summary> /// 带事务的插入方法 /// </summary> /// <param name="t"></param> /// <returns></returns> public int InsertByTran(T t) { try { Type mytype = t.GetType(); // 获取类的所有公共属性 System.Reflection.PropertyInfo[] pInfo = mytype.GetProperties(); string FieldName = "";//字段名称 string Values = "";//值 StringBuilder sql = new StringBuilder(); List<SqlParameter> paras = new List<SqlParameter>(); sql.Append("Insert into ["); sql.Append(mytype.Name);//数据库表名 sql.Append("]("); object[] objDataFieldAttribute = null; foreach (System.Reflection.PropertyInfo pio in pInfo) { objDataFieldAttribute = pio.GetCustomAttributes(typeof(DataFieldAttribute), false); if (objDataFieldAttribute != null && objDataFieldAttribute.Length > 0) { FieldName += ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName + ","; Values += "@" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName + ","; paras.Add(new SqlParameter("@" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName, pio.GetValue(t, null))); } } FieldName = FieldName.TrimEnd(','); Values = Values.TrimEnd(','); sql.Append(FieldName); sql.Append(") VAlUES ("); sql.Append(Values); sql.Append(")"); int i = SqlHelper.ExecuteNonQuery(tran, CommandType.Text, sql.ToString(), paras.ToArray()); return i; } catch (Exception) { tran.Rollback(); return -1; throw; } } /// <summary> /// 带事务的更新方法 /// </summary> /// <param name="t"></param> /// <returns></returns> public int UpdateByTran(T t) { try { int i = 0; int primarykey = t.ID; T oldT = t; Type mytype = t.GetType(); System.Reflection.PropertyInfo[] pInfo = mytype.GetProperties(); oldT = SelectByID(primarykey, oldT);//获得原始值,为日志做准备 if (t != oldT) { string SetValue = "";//字段名称 string Where = " where ID=@ID";//值 StringBuilder sql = new StringBuilder(); List<SqlParameter> paras = new List<SqlParameter>(); sql.Append("Update ["); sql.Append(mytype.Name); sql.Append("] Set "); object[] objDataFieldAttribute = null; foreach (System.Reflection.PropertyInfo pio in pInfo) { objDataFieldAttribute = pio.GetCustomAttributes(typeof(DataFieldAttribute), false); if (objDataFieldAttribute != null && objDataFieldAttribute.Length > 0 && pio.GetValue(t, null).ToString() != pio.GetValue(oldT, null).ToString()) { SetValue += ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName + "=" + "@" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName + ","; paras.Add(new SqlParameter("@" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName, pio.GetValue(t, null))); } } SetValue = SetValue.TrimEnd(','); sql.Append(SetValue); sql.Append(Where); paras.Add(new SqlParameter("@ID", primarykey)); i = SqlHelper.ExecuteNonQuery(tran, CommandType.Text, sql.ToString(), paras.ToArray()); return i; } else { tran.Rollback(); return -2; } } catch (Exception) { tran.Rollback(); return -1; throw; } } /// <summary> /// 带事务的删除方法 /// </summary> /// <param name="t"></param> /// <returns></returns> public int DeleteByTran(T t) { int i = 0; int primarykey = t.ID; Type mytype = t.GetType(); string TableName = mytype.Name; string Where = "] where ID =@ID"; string sql = "DELETE FROM [" + TableName + Where; try { i = SqlHelper.ExecuteNonQuery(tran, CommandType.Text, sql, new SqlParameter("@ID", primarykey)); return i; } catch (Exception) { tran.Rollback(); return -1; throw; } } /// <summary> /// 带事务和条件的删除方法 /// </summary> /// <param name="t"></param> /// <returns></returns> public int DeleteByTran(T t, string where) { if (where.IndexOf("1=1") > 0) { return -1; } int i = 0; string Where = "] where " + where; string sql = "DELETE FROM [" + t.TableName + Where; try { i = SqlHelper.ExecuteNonQuery(tran, CommandType.Text, sql, null); return i; } catch (Exception) { tran.Rollback(); return -1; throw; } } /// <summary> /// 提交事务 /// </summary> /// <returns></returns> public void CommitTran() { try { tran.Commit(); conn.Close(); } catch (Exception) { tran.Rollback(); conn.Close(); throw; } finally { tran.Dispose(); conn.Dispose(); } } /// <summary> /// 回滚事务 /// </summary> public void RollBackTran() { try { tran.Rollback(); } catch (Exception) { throw; } } }}
好了,整个ORM就写完了,这样我们数据处理的类就写完了!
三:Domain层
ORM写完后,因为不同的表可能在不同的库中,所以ZeroORM还不能直接拿来用,需要在上面隔离一层,我们这里选择最简单的方式,大牛勿喷。
首先写一个Repository基类(这里就不抽象类了),代码如下
using System;using System.Collections.Generic;using System.Linq;using System.Text;using Zero.Domain.Abstract;using Zero.Infrastructure.IBase;namespace Zero.Domain.Concrete{ public class ConcreteBase<T> where T : IDataBase { public Zero.Infrastructure.Conntion.ZeroORM<T> DbHelper; public ConcreteBase() { DbHelper = new Infrastructure.Conntion.ZeroORM<T>(); } public string SqlConnctionString { get { return DbHelper.SqlConnctionString; } set { DbHelper.SqlConnctionString = value; } } public List<T> GetAllList(T t) { List<T> ubiList = new List<T>(); ubiList = DbHelper.Select(t); return ubiList; } public bool Insert(T t) { int i = 0; i = DbHelper.Insert(t); return i > 0; } public bool Update(T t) { int i = 0; i = DbHelper.Update(t); return i > 0; } public bool Delete(T t) { int i = 0; i = DbHelper.Delete(t); return i > 0; } /// <summary> /// 带事务的插入方法 /// </summary> /// <param name="t"></param> /// <returns></returns> public bool InsertByTran(T t) { if (DbHelper.tran == null) { DbHelper.BeginTran(); } int i = DbHelper.InsertByTran(t); return i > 0; } /// <summary> /// 带事务的更新方法 /// </summary> /// <param name="t"></param> /// <returns></returns> public bool UpdateByTran(T t) { if (DbHelper.tran == null) { DbHelper.BeginTran(); } int i = DbHelper.UpdateByTran(t); return i > 0; } /// <summary> /// 带事务的删除方法 /// </summary> /// <param name="t"></param> /// <returns></returns> public bool DeleteByTran(T t) { if (DbHelper.tran == null) { DbHelper.BeginTran(); } int i = DbHelper.DeleteByTran(t); return i > 0; } /// <summary> /// 带事务和条件的删除方法 /// </summary> /// <param name="t"></param> /// <returns></returns> public bool DeleteByTran(T t, string where) { if (DbHelper.tran == null) { DbHelper.BeginTran(); } int i = DbHelper.DeleteByTran(t, where); return i > 0; } /// <summary> /// /// </summary> /// <param name="t"></param> /// <returns></returns> public void RollBackTran() { DbHelper.RollBackTran(); } /// <summary> /// /// </summary> /// <param name="t"></param> /// <returns></returns> public void BeginTran() { DbHelper.BeginTran(); } /// <summary> /// 提交事务 提交成功返回"";失败返回错误信息 /// </summary> /// <returns>提交成功返回"";失败返回错误信息</returns> public string CommitTran() { if (DbHelper.tran != null) { try { DbHelper.CommitTran(); return ""; } catch (Exception e) { return e.ToString(); throw; } } else { return "不存在可提交的事务"; } } /// <summary> /// 根据主键ID查询结果,返回T /// </summary> /// <param name="id"></param> /// <returns></returns> public T SelectByID(string id, T t) { if (id != "") { return DbHelper.SelectByID(int.Parse(id), t); } else { return null; } } }}
然后去写Repository类和IRepository接口
using System;using System.Collections.Generic;using System.Linq;using System.Text;using Zero.Domain.Entities;namespace Zero.Domain.Abstract{ public interface IUserRepository { User GetEntity(); IQueryable<User> Users { get; } }}
实现类:
using System;using System.Collections.Generic;using System.Configuration;using System.Linq;using System.Text;using Zero.Domain.Abstract;using Zero.Domain.Entities;namespace Zero.Domain.Concrete{ public class UserRepository : ConcreteBase<User>, IUserRepository { public User GetEntity() { return new User(); } public IQueryable<User> BaseTitleTypes { get { return GetAllList(GetEntity()).AsQueryable(); } } public UserRepository() : base() { SqlConnctionString = ConfigurationManager.ConnectionStrings["ZeroTest"].ConnectionString;//获取连接字符串 } }}
然后去数据库建表
链接字符串的位置写的有点蠢,不过先这样做吧,一切已快速为目的
现在,所有的准备工作都做完了,开始测试一下数据交互是否有问题!
在Zero项目中建一个Index控制器
然后右键Index添加视图。先不做IOC解耦,引用Domain层和基础设施层。
添加如下代码
// // GET: /Index/ public ActionResult Index() { UserRepository us = new UserRepository(); bool b =us.Insert(new Domain.Entities.User { UserName = "Ambre" }); if (b) { var ListEntity = from o in us.Users select o; return Json(ListEntity, JsonRequestBehavior.AllowGet); } else { return Content(b.ToString()); } }
然后去改下路由设置
启动项目
好了,完成!下篇文章将写如何快速的将IOC应用到项目中,然后前端类似于EasyUi的grid控件如何编写。
谢谢大家,喜欢的话,点个赞,这可是我的处女文呢!
新闻热点
疑难解答