ADO.NET 问题,欢迎各路大神进行点评

Hmg-L 2014-10-12 05:10:06
首先因为对EF不熟悉,所以采用MVC4+ado.net构架项目底层!

数据库采用灵动性的,方便以后进行切换的。所以有了个入口


/// <summary>
/// 数据提供入口
/// </summary>
public class DataProvider
{
/// <summary>
/// 数据库枚举类型
/// </summary>
public enum DataProviderType
{
/// <summary>
/// My SQL data provider
/// </summary>
MySqlDataProvider,
/// <summary>
/// The SQL Server data provider
/// </summary>
MsSqlDataProvider,
/// <summary>
/// The oracle data provider
/// </summary>
OracleDataProvider,
}

/// <summary>
/// 建立数据提供商
/// </summary>
/// <param name="dataProviderType">数据提供商类型提供</param>
/// <returns>数据提供商</returns>
public static IDataProvider CreateProvider(DataProviderType dataProviderType)
{
switch (dataProviderType)
{
case DataProviderType.MySqlDataProvider:
return new MySqlDataProvider();
case DataProviderType.MsSqlDataProvider:
return new MsSqlDataProvider();
default:
return null;

}
}
}


同时提供了一个接口,来调用数据库提供者的数据。


/// <summary>
/// SQL数据提供者
/// </summary>
public interface IDataProvider
{
/// <summary>
/// (无参)检测是否存在.
/// </summary>
/// <param name="strSql">The string SQL.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
bool Exists(string strSql);
/// <summary>
/// 检测是否存在.
/// </summary>
/// <param name="strSql">The string SQL.</param>
/// <param name="dataParameters">The data parameters.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
bool Exists(string strSql, IDataParameter[] dataParameters);
/// <summary>
/// 对连接执行 Transact-SQL 语句并返回受影响的行数
/// </summary>
/// <param name="strSql">The string SQL.</param>
/// <returns>System.Int32.</returns>
int ExecuteNonQuery(string strSql);
/// <summary>
/// Executes the non query.
/// </summary>
/// <param name="strSql">The string SQL.</param>
/// <param name="dataParameters">The data parameters.</param>
/// <returns>System.Int32.</returns>
int ExecuteNonQuery(string strSql, IDataParameter[] dataParameters);
/// <summary>
/// Queries the specified to string.
/// </summary>
/// <param name="toString">To string.</param>
/// <returns>DataSet.</returns>
DataSet Query(string toString);
/// <summary>
/// 返回一个DataSet(查询相关).
/// </summary>
/// <param name="toString">To string.</param>
/// <param name="parameters">The parameters.</param>
/// <returns>DataSet.</returns>
DataSet Query(string toString, IDataParameter[] parameters);
/// <summary>
/// (无参)执行查询,并返回查询所返回的结果集中第一行的第一列。忽略其他列或行.
/// </summary>
/// <param name="strSql">The string SQL.</param>
/// <returns>System.Object.</returns>
object ExecuteScalar(string strSql);
/// <summary>
/// 执行查询,并返回查询所返回的结果集中第一行的第一列。忽略其他列或行.
/// </summary>
/// <param name="strSql">The string SQL.</param>
/// <param name="dataParameters">The data parameters.</param>
/// <returns>System.Object.</returns>
object ExecuteScalar(string strSql, IDataParameter[] dataParameters);
/// <summary>
/// 添加一条数据
/// </summary>
/// <typeparam name="T">Model</typeparam>
/// <param name="t1">Model model</param>
/// <returns>System.Int32.</returns>
int Add<T>(T t1);
/// <summary>
/// 更新一条或多条数据
/// </summary>
/// <typeparam name="T">Model</typeparam>
/// <param name="t1">Model model</param>
/// <param name="strWhere">查询条件
/// (注:不用加where)</param>
/// <param name="whereObjects">where条件的参数
/// 如:where 条件 Name=@Name 在此为new{Name=name}</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
bool Update<T>(T t1, string strWhere = null, object whereObjects = null);


不知不觉中,回到了三层架构。但是我想让调用方便且controller中不出现sql语句,于是封装了两套调用,一套是正常三层,一套是反射生成sql语句。

代码如下:
正常三层:

/// <summary>
/// 更新一条数据
/// </summary>
public static bool Update(User model)
{
StringBuilder strSql = new StringBuilder();
strSql.Append("update user set ");
strSql.Append("Name=@Name,");
strSql.Append("AddTime=@AddTime");
strSql.Append(" where Id=@Id");
IDataParameter[] parameters = {
new MySqlParameter("@Name", MySqlDbType.VarChar,45),
new MySqlParameter("@AddTime", MySqlDbType.DateTime),
new MySqlParameter("@Id", MySqlDbType.Int32,11)};
parameters[0].Value = model.Name;
parameters[1].Value = model.AddTime;
parameters[2].Value = model.Id;

int rows = myDataProvider.ExecuteNonQuery(strSql.ToString(), parameters);
if (rows > 0)
{
return true;
}
else
{
return false;
}
}


反射调用:

/// <summary>
/// 更新一条或多条数据
/// </summary>
/// <typeparam name="T">Model</typeparam>
/// <param name="t1">Model model</param>
/// <param name="strWhere">查询条件
/// (注:不用加where)</param>
/// <param name="whereObjects">where条件的参数
/// 如:where 条件 Name=@Name 在此为new{Name=name}</param>
/// <returns></returns>
public bool Update<T>(T t1, string strWhere = null, object whereObjects = null)
{
Type t = t1.GetType();
StringBuilder strSql = new StringBuilder();
strSql.Append("update " + t.Name + " set ");
List<string> members = new List<string>();
var listWhere = new List<string>();
var l = new List<IDataParameter>();

//遍历所有属性
foreach (PropertyInfo pi in t.GetProperties())
{
var value = pi.GetValue(t1, null);//用pi.GetValue获得值
var name = pi.Name; //获得属性的名字,后面就可以根据名字判断来进行些自己想要的操作
//没有复制的属性和Id都不予以生成sql主句
if (value == null)
{
continue;
}
l.Add(new MySqlParameter("@" + name, value));
//如果Id(主键)被赋值,那么将主键作为where语句
if (name == "Id")
{
listWhere.Add(" and Id=@Id");
continue;
}
members.Add(name + " = @" + name);
}
strSql.Append(string.Join(",", members.ToArray()));
strSql.Append(" where 1=1 ");
strSql.Append(string.Join("", listWhere.ToArray()));

if (whereObjects != null)
{
strSql.Append(" and " + strWhere);
PropertyInfo[] pis = whereObjects.GetType().GetProperties();
foreach (var pi in pis)
{
l.Add(new MySqlParameter("@" + pi.Name, pi.GetValue(whereObjects, null)));
}
}
int rows = ExecuteNonQuery(strSql.ToString(), l.ToArray());
if (rows > 0)
{
return true;
}
else
{
return false;
}
}


最后,我想请教一下各位:
1. 鄙人此举,会不会对以后的优化带来障碍?
2. 若我全部采用反射sql语句来实现,多表关联查询我该如何设计?
3. 有写过类似底层的大神,请给一点思路,或者一段代码,点醒我。

小可在此不胜感激。
...全文
481 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
Hmg-L 2014-10-16
  • 打赏
  • 举报
回复
谢谢各位,我的底层已经写好再用了。感谢sp,insus 两位大神的思路点醒。感谢wyumening,sj178220709的技术代码纠正,再次感谢,小弟结贴了
threenewbee 2014-10-13
  • 打赏
  • 举报
回复
你实在应该使用EF,它没有你想象的那么难学。
Justin-Liu 2014-10-13
  • 打赏
  • 举报
回复
EF挺好的啊,我用了EF之后就不爱用SQL语句了
Hmg-L 2014-10-13
  • 打赏
  • 举报
回复
谢谢各位的建议。 我想我解决掉了。 代码如下: Model:

 public class User :BaseModel<User>
    {
        public int? Id { get; set; }
        public string Name { get; set; }
        public DateTime? AddTime { get; set; }
    }

    public class BaseModel<T> where T :  new()
    {
        /// <summary>
        /// 数据库提供商选择
        /// </summary>
        protected IDataProvider MySqlDataProvider =
            DataProvider.CreateProvider(DataProvider.DataProviderType.MySqlDataProvider);
        public virtual int Add(T model)
        {
            return MySqlDataProvider.Add(model);
        }

    }
调用方法:

            //添加一条
            sw.Restart();
            User u4 = new User();
            u4.Name = "董西刚";
            u4.AddTime = DateTime.Now;
            //Console.WriteLine(Add<User>(u4));
            Console.WriteLine(u4.Add(u4));
            sw.Stop();
            Console.WriteLine("更新运行时间:" + sw.Elapsed.TotalMilliseconds);
这样的调用已经开始方便起来了,对于以后的优化,目前还没有思路。 有好的建议吗?
Hmg-L 2014-10-13
  • 打赏
  • 举报
回复
引用 11 楼 caozhy 的回复:
你实在应该使用EF,它没有你想象的那么难学。
感谢版主的建议。 我自学过一段时间的EF,但是在没有精通之前,不敢拿来作为客户的框架,会出人命的
Hmg-L 2014-10-13
  • 打赏
  • 举报
回复
引用 10 楼 insus 的回复:
Refer hter: http://zzk.cnblogs.com/s?w=blog%3Ainsus%20ASP.NET%E5%BC%80%E5%8F%91%EF%BC%8C%E4%BB%8E%E4%BA%8C%E5%B1%82%E8%87%B3%E4%B8%89%E5%B1%82%EF%BC%8C%E8%87%B3%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1
感谢insus大神进行回复,您的帖子我以前也看过一些,都写得很详细,通俗易懂。 但是在这次的帖子中我发现您拒绝用反射来获取Model的属性,想问下原因是什么呢? 我觉得用上反射的话,不仅能够简化model(不再model中写sql语句,比如GetAll()等方法,等都可拿出来重新封装),而且结构上更清晰。 还有就是,如果采用我以上的思路(其实我原来的想法就和您的想法很接近了),如采用: Model.Add(model); 此种方法,我该如何进行分装? (也就是把除Model属性之外的所有方法提取出来,作为一个类,任何Model都可以调用) 请进行指点,谢谢
myhope88 2014-10-13
  • 打赏
  • 举报
回复
我也是来学习的
qzyf1992 2014-10-13
  • 打赏
  • 举报
回复
大胆用年轻怕什么
  • 打赏
  • 举报
回复
推荐楼主研究下两种orm dapper 和iBatis 前者是通过你这种方式,根据反射自动生成sql语句 后者是自己写sql,去映射不同的poco(DTO) Ps:dapper有很多种扩展,有的方式也是基于sql去匹配poco,和iBatis很像.
  • 打赏
  • 举报
回复
还是直接使用ORM吧
wyumening 2014-10-13
  • 打赏
  • 举报
回复
引用 16 楼 feng005211 的回复:
谢谢各位的建议。 我想我解决掉了。 代码如下: Model:

 public class User :BaseModel<User>
    {
        public int? Id { get; set; }
        public string Name { get; set; }
        public DateTime? AddTime { get; set; }
    }

    public class BaseModel<T> where T :  new()
    {
        /// <summary>
        /// 数据库提供商选择
        /// </summary>
        protected IDataProvider MySqlDataProvider =
            DataProvider.CreateProvider(DataProvider.DataProviderType.MySqlDataProvider);
        public virtual int Add(T model)
        {
            return MySqlDataProvider.Add(model);
        }

    }
调用方法:

            //添加一条
            sw.Restart();
            User u4 = new User();
            u4.Name = "董西刚";
            u4.AddTime = DateTime.Now;
            //Console.WriteLine(Add<User>(u4));
            Console.WriteLine(u4.Add(u4));
            sw.Stop();
            Console.WriteLine("更新运行时间:" + sw.Elapsed.TotalMilliseconds);
这样的调用已经开始方便起来了,对于以后的优化,目前还没有思路。 有好的建议吗?
你自己也说了这种反射sql(尽量去依赖model)的做法,即破坏了三层,又在向EF靠拢。 那你到底要实现什么目的呢? 如果是为了实现三层下的数据库切换,就去看看 应用了抽象工厂模式的三层架构是怎么做的,网上搜一搜就有了,如果是想用ORM,就学习下EF的使用,然后在项目中用EF就行了,如果是对ado.net不了解,就去了解ado.net就行了
游离失所 2014-10-13
  • 打赏
  • 举报
回复
public class BaseModel<T> where T : class, new()
游离失所 2014-10-13
  • 打赏
  • 举报
回复
引用 16 楼 feng005211 的回复:
谢谢各位的建议。 我想我解决掉了。 代码如下: Model:

 public class User :BaseModel<User>
    {
        public int? Id { get; set; }
        public string Name { get; set; }
        public DateTime? AddTime { get; set; }
    }

    public class BaseModel<T> where T :  new()
    {
        /// <summary>
        /// 数据库提供商选择
        /// </summary>
        protected IDataProvider MySqlDataProvider =
            DataProvider.CreateProvider(DataProvider.DataProviderType.MySqlDataProvider);
        public virtual int Add(T model)
        {
            return MySqlDataProvider.Add(model);
        }

    }
调用方法:

            //添加一条
            sw.Restart();
            User u4 = new User();
            u4.Name = "董西刚";
            u4.AddTime = DateTime.Now;
            //Console.WriteLine(Add<User>(u4));
            Console.WriteLine(u4.Add(u4));
            sw.Stop();
            Console.WriteLine("更新运行时间:" + sw.Elapsed.TotalMilliseconds);
这样的调用已经开始方便起来了,对于以后的优化,目前还没有思路。 有好的建议吗?
这样写也没问题。。但是u4.Add(u4)。。这里看起来不是很奇怪吗? public virtual int Add() { return MySqlDataProvider.Add(this as T); } 调用时直接u4.Add();
insus 2014-10-13
  • 打赏
  • 举报
回复
Insus.NET对于反射的使用,能不用反射就不用。另外Insus.NET开发过程中,写存储过程写得多,还是较习惯写SQL语句,因此基不上不使用EF。
Hmg-L 2014-10-12
  • 打赏
  • 举报
回复
怎么没人回答了 指导啊,思路啊,代码段啊,资料链接啊 帮帮我这位渴望成长的人儿吧
Hmg-L 2014-10-12
  • 打赏
  • 举报
回复
引用 5 楼 sp1234 的回复:
自己开发一个 ORM,最难做到的就是让 ORM 架构自动产生“查询语句”。 你总是纠结“增、删、改”干啥啊?你应该跟着“查询语句”开发方面的技术层次走,而不是为了低级的“增删改”而邯郸学步。 没有这些,那么也不要盲目抄袭网上的一些所谓的“三层框架”文章里边的繁琐招数。给自己的开发效率舔麻烦,并不能让你显得更技术。 做同一个东西,就算是东施学西施的一颦一笑,它自身也是有去别的,没有把握这个区别,你就会把一个好事情办砸
sp大神的这些话,的确对我是一个指引,也是一个提醒,真的,我恍惚仿佛间看到另一个技术层次。 觉得自己就像井底之蛙一样,傻傻分不清楚,在自己的死胡同里乱转。 然后脑子里突然蹦出个dynamic eo = new ExpandoObject();,可以用这个动态类型做很多事情。 在做这个ado.net之前,我翻阅了大量网上的资料,但是还是对此认识不够。 同时提醒自己,真的要多读书了,不然靠网络的资料,真的是提升有限。
  • 打赏
  • 举报
回复
引用 3 楼 feng005211 的回复:
一直用别人的,自己不去理解,会感觉自己很渣。 我用动软生成的底层用了半年,去面试的时候,人家问你用的什么ado.net,我两眼一瞪,说不知道。人家轻笑一声,谢谢您这次的面试,直接结束了。 还是自己多折腾吧。
面试时,如果面试官仅仅因为这样一个问题而对你有了“见解”,那么他可能也没有设计过什么东西。 既不会因为你“用了动软而不懂ado.net”的这个原因,也不会因为是你自己用了ado.net而不用动软的原因。人家是觉得你研究的东西的层次,跟应用开发不符。 做同一个东西,就算是东施学西施的一颦一笑,它自身也是有去别的。就好像你没有搞明白“查询”而偏要纠结“增删改”一样。没有把握这个区别,你就会把一个好事情办砸。
Hmg-L 2014-10-12
  • 打赏
  • 举报
回复
引用 4 楼 sp1234 的回复:
这样写没有多大意义。 切换不同种类的 sql 语句,只要切换字符串资源就行了,剩下的 ADO.NET 驱动部分本来就是完全抽象的(编程中不需要考虑Sql、Ole还是Oracle)。
感谢sp大神的回复。 可能是因为自己的原因吧,想把他们区分开,感觉更清晰一点。 其实我还想问一下,对于我这种反射sql(尽量去依赖model)的做法,您的看法和指导,因为我破坏了三层,又在向EF靠拢。
加载更多回复(5)

62,046

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧