用基础知识实现数据到模型的填充

  目前的开发中,我们一般会从数据库查询出来数据,再把数据填充到一个对象中,然后就可以很方便的读取对象信息了。data填充到object这个过程很是繁琐,为简化这个问题,各种框架、组件层出不穷,在此不一一列举,我实在也列举不出
-_- !  诸多框架用起来固然方便,但我总会想起一句话,原文模糊了,出处忘了,大意是“当到一定程度时技术都会以各自的方式失败”,且不说失败不失败,用框架的同学在某个时刻肯定有过这样的感慨:“要是这个框架支持XX就好了”、“这个功能本来很简单,但我们项目现在用的是这个框架,要实现这个功能看来又要写蹩足的代码了”、“这个框架越来越不符合我们的要求,难道我们要改成YY框架吗?”等等。所以框架都有自身固有的限制,那么我们面临的问题,第一时间真的都要求助于框架吗?

本文想表达的决无轻视框架的意思,只是园里讨论框架的甚多,往往让新手有一种不了解、不会用某某框架就说明自己差人一大截的感觉,同时也让很多新手只因会用很多框架就感觉自己很牛B的样子,不管是哪种情况,都不利于自身技术上的提高。所以此文是只是希望新手们能深刻思考一下自己的现状,给自己一个正确的评估,努力做到看到如何调用时,就大概能想象出内部是如何实现的,说白了就是对语言本身很熟悉,对一些思想有了解,下面不表框架的种种,单用新手都知道的技术组合出一个data到object的实现。

准备及问题:

  准备1,数据库test1有表MyUser{

    ID (PK, int, not null)

    UserName (varchar(20), not null)

    Age (tinyint, not null)

    Birthday (datetime, null)

  }

  准备2,数据库test2有表Message{

    ID (PK, int, not null)

    MyUserID (int, not null)

    Content (nvarchar(200), not null)

    AddTime (datetime, not null)

  }

准备3,SQLHelper一个,这个自不必说,访问数据库嘛!

  问题1,一个data到object的填充只实现一次,不管是取多少个字段,不管是取一条数据还是多条数据

  问题2,关联查询,为了强调演示,关联数据在不同的数据库里,具体就是查用户和他们的消息(可能用动态和评论来举例更合适,呵呵 谅解!)

 思考:

  想重用,自然而然的就会想到继承;

  想统一处理,也要想到抽象;

  想动态添加数据,要能想到字典,大家一定要记得,字典是一个很好用的数据结构

  想用统一的方法得到不同的具体的类型对象,自然是泛型了。

  下方会一一体现,现在不明所以没关系。

 实现:

  data到object的填充,具体到ado.net,一般就是reader到object了,要实现动态字段都用一个方法填充,以MyUser来说,大概可以这样:


public MessageInfo FillModelFromReader(DbDataReader reader, params string[] fields)
{
var info = new MessageInfo();
if (DALUtil.HasFields("ID", fields)) { info.ID = (int)reader["ID"]; }
if (DALUtil.HasFields("MyUserID", fields)) { info.MyUserID = (int)reader["MyUserID"]; }
if (DALUtil.HasFields("Content", fields)) { info.Content = reader["Content"].ToString(); }
if (DALUtil.HasFields("AddTime", fields)) { info.AddTime = (DateTime)reader["AddTime"]; }
return info;
}

  数据库交互无非就那几个方法,我们可以抽象出来一个数据访问的基类,实际运用中还要写几个方法重载,以便于调用

    /// <summary>
/// DAL基类
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class DALBase<T>
{
/// <summary>
/// 由子类决定用哪个链接
/// </summary>
protected abstract string ConnName
{
get;
}

protected abstract T FillModelFromReader(DbDataReader reader, params string[] fields);

protected string GetConnStr()
{
return System.Configuration.ConfigurationManager.ConnectionStrings[ConnName].ConnectionString;
}

protected List<T> FindList(string sql, CommandType type, params SqlParameter[] parameters)
{
using (var reader = SqlHelper.ExecuteReader(GetConnStr(), type, sql, parameters))
{
List<T> list = new List<T>();
var fields = DALUtil.GetReaderFieldNames(reader);
while (reader.Read())
{
list.Add(FillModelFromReader(reader, fields));
}
return list;
}
}

protected T FindOne(string sql, CommandType type, params SqlParameter[] parameters)
{
return FindList(sql, type, parameters).FirstOrDefault();
}

private List<T> FindPage(string tableName, string fields, string query, string orderby, int pageIndex, int pageSize, bool isTotal, out int totalCount, params SqlParameter[] parameters)
{
if (pageIndex < 1)
{
throw new ArgumentException("pageIndex参数应>1");
}

StringBuilder sb = new StringBuilder();
SqlParameter[] newPs;
if (isTotal)
{
sb.AppendFormat("select count(0) from [{0}]", tableName);
if (!string.IsNullOrWhiteSpace(query))
{
sb.AppendFormat(" where {0}", query);
}
totalCount = GetCount(sb.ToString(), parameters);
sb.Clear();
newPs = SqlHelper.CopyParameters(parameters);
}
else
{
newPs = parameters;
totalCount = 0;
}

if (string.IsNullOrWhiteSpace(orderby))
{
throw new ArgumentException("orderby参数不应为空");
}

var fs = string.IsNullOrWhiteSpace(fields) ? "*" : string.Join(",", fields);
sb.AppendFormat("select {0} from (", fs);
sb.AppendFormat(" select top {0} {1},ROW_NUMBER() over(order by {2}) rowid from {3}", pageIndex * pageSize, fs, orderby, tableName);
if (!string.IsNullOrWhiteSpace(query))
{
sb.AppendFormat(" where {0}", query);
}
sb.AppendFormat(")t where t.rowid>{0} and t.rowid<={1}", (pageIndex - 1) * pageSize, pageIndex * pageSize);

return FindList(sb.ToString(), CommandType.Text, newPs);
}

protected object GetScalar(string sql, CommandType type, params SqlParameter[] parameters)
{
return SqlHelper.ExecuteScalar(GetConnStr(), type, sql, parameters);
}

protected int GetCount(string sql, CommandType type, params SqlParameter[] parameters)
{
var obj = GetScalar(sql, type, parameters);
if (obj == null) return -1;
return (int)obj;
}

protected int Execute(string sql, CommandType type, params SqlParameter[] parameters)
{
return SqlHelper.ExecuteNonQuery(GetConnStr(), type, sql, parameters);
}
}

  实现MyUserDAL,继承于DALBase<MyUserInfo>,设置自己的链接名,实现自己的填充方法,而所有的查询直接调用基类的方法即可,不管哪个查询,都会在基类调用自己实现的填充方法!这样问题1算是解决了。(模型和FillModelFromReader都是用MyGeneration)


public class MyUserDAL : DALBase<MyUserInfo>
{
protected override string ConnName
{
get { return "sqlconn1"; }
}

protected override MyUserInfo FillModelFromReader(DbDataReader reader, params string[] fields)
{
var info = new MyUserInfo();
if (DALUtil.HasFields("ID", fields)) info.ID = (int)reader["ID"];
if (DALUtil.HasFields("UserName", fields)) info.UserName = reader["UserName"].ToString();
if (DALUtil.HasFields("Age", fields)) info.Age = (byte)reader["Age"];
if (DALUtil.HasFields("Birthday", fields) && !(reader["Birthday"] is DBNull)) info.Birthday = (DateTime)reader["Birthday"];
return info;
}

public MyUserInfo FindOne(int id)
{
var sql = "select * from MyUser where [email protected]";
return FindOne(sql, DALUtil.CreateParameter("id", id));
}

public List<MyUserInfo> Find1()
{
var sql = "select ID,UserName from MyUser";
return FindList(sql);
}

public List<MyUserInfo> Find2()
{
var sql = "select ID,UserName,Age,Birthday from MyUser";
return FindList(sql);
}
}

  问题2是表关联问题,这个时候要想到字典,字典这个东西真是再强调也不为过啊。对于UI层,我们取数据是从模型来的,所以关联数据也要在模型上,我们为需要关联数据的模型建一个基类,关联数据其实可以理解为附加数据的一种,所以我们以后叫它附加数据:


    /// <summary>
/// 模型层附加数据基类
/// </summary>
[Serializable]
public class ModelBase
{
private Dictionary<string, object> _exData = new Dictionary<string, object>();

public Dictionary<string, object> ExData
{
get { return _exData; }
set { _exData = value; }
}

/// <summary>
/// 得到附加数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
public T GetExData<T>(string name)
{
object data;
if (_exData.TryGetValue(name, out data))
{
return (T)data;
}
return default(T);
}

/// <summary>
/// 添加附加数据
/// </summary>
/// <param name="name"></param>
/// <param name="obj"></param>
public void AddExData(string name, object obj)
{
_exData.Add(name, obj);
}

/// <summary>
/// 检测附加数据是否存在
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public bool ExistsExData(string name)
{
return _exData.ContainsKey(name);
}
}

  MyUserInfo有附加数据,那么就让MyUserInfo继承ModelBase吧,继承后便有了存储附加数据的能力,而附加数据这个操作写到哪里呢?当然是写到BLL里,首先实现Message的相关功能,这里我们需要一个public
List<MessageInfo> FindByUserIDs(IEnumerable<int>
userids)的方法来根据一串userid得到一个MessageInfo的集合,代码不贴了,下附下载。直接看MyUserBLL里的操作:


    public class MyUserBLL
{
DAL.MyUserDAL dal = new DAL.MyUserDAL();

public MyUserInfo FindOne(int id)
{
return dal.FindOne(id);
}

public List<MyUserInfo> Find1()
{
var list = dal.Find1();
return list;
}

public List<MyUserInfo> Find2()
{
var list = dal.Find2();
DealMsg(list);
return list;
}

static void DealMsg(List<MyUserInfo> list)
{
var ids = list.Select(u => u.ID);
MessageBLL msgbll = new MessageBLL();
var msgs = msgbll.FindByUserIDs(ids);
foreach (var info in list)
{
info.AddExData("Messages", msgs.Where(msg => msg.MyUserID == info.ID).ToList());
}
}
}

  一个DealMsg方法,便来自两个数据库的数据连接到一起了,像DealXX的方法可以根据需要要以有多个,分别附加不的数据,再看测试:


    class Program
{
static MyUserBLL userbll = new MyUserBLL();
static void Main(string[] args)
{
F0();
Console.WriteLine();
F1();
Console.WriteLine();
F2();
}

static void F0()
{
var info = userbll.FindOne(2);
Console.WriteLine(info.ToString());
}

static void F1()
{
var list = userbll.Find1();
foreach (var info in list)
{
Console.WriteLine(info.ToString());
}
}

static void F2()
{
var list = userbll.Find2();
foreach (var info in list)
{
Console.WriteLine(info.ToString());
var messages = info.GetExData<List<MessageInfo>>("Messages");
foreach (var msg in messages)
{
Console.WriteLine("\t{0}", msg.ToString());
}
Console.WriteLine();

}
}
}

至此收工!

很多简单的东西掌握好了,组合起来也能做一些事件吧!

下载

时间: 2024-10-10 11:26:24

用基础知识实现数据到模型的填充的相关文章

Android基础知识(6)—数据持久化之数据存储

阅读前,请浏览此处上方目录. Android基础知识(6)-数据持久化之数据存储 本章内容为个人笔记,参考书籍有:<疯狂的android>第3版.<第一行代码> 首先,我们要知道什么是数据持久化. 数据持久化就是指那些内存中的瞬时数据保存到存储设备中,保证即使手机在关机的情况下,这些数据不会丢失.保存在内存中的数据是处于瞬时状态,保存在存储设备中的数据是处于持久状态.持久化技术则是提供了一种机制可以让数据在瞬时状态和持久状态之间进行转换. Android系统主要提供了三种方式用于简

iOS开发基础知识之数据下载

1数据下载 简介: (1)在本文中笔者将给大家带来一些网络基础知识的介绍,NSURLConnection从网络上下载数据的方式,以及如何利用利用同步,异步下载显示图片和数据. 1网络基础知识 什么是网络应用? 1 网络应用软件是用户利用软件开发平台,按照各自需要开发的各种各样的网上业务应用系统.常见的开发平台有各种数据库管理系统.办公自动化管理系统以及浏览器.网页制作网站管理等软件. 2客户端与服务端 网络应用不同于本地应用, 网络应用的数据是从网络上下载下来的, 所以需要在网络上运行一个程序为

Android学习之基础知识九 — 数据存储(持久化技术)之使用LitePal操作数据库

上一节学习了使用SQLiteDatabase来操作SQLite数据库的方法,接下来我们开始接触第一个开源库:LitePal.LitePal是一款开源的Android数据库框架,它采用了对象关系映射(ORM)的模式,并将我们平时开发最常用到的一些数据库功能进行了封装,使得不用编写一行SQL语句就可以完成各种建表和增删改查的操作,LitePal的项目主页上也有详细的使用文档,地址是: https://github.com/LitePalFramework/LitePal 一.配置LitePal 要在

c++基础知识学习-----数据程序的储存、表示形式和基本运算

刚开始学习c++  ,看书总结了一点注意事项,一来记录下来方便后续查看,二来希望可以对和我一样的小白有点帮助 数据程序的储存.表示形式和基本运算 1.1/1.2(书本的章节){1.输入时内容之间用空格隔开 2.函数的声明与命名相似,仅需在主函数中函数调用之前将函数的命名后加分号写入主函数中即可声明 3.C++的输出格式:cout<<输出内容<<endl :输入格式:cin>>输入内容: 4.主函数一般定义为int型:是则返回1,否则返回0: 5.命名空间的名字是不能重复

keepalive基础知识及主备模型搭建

lvs模型属于单点故障,对real server的健康状态检查可以通过写脚本实现,keepalived可以实现高可用: keepalive:vrrp协议在Linux主机上以守护进程方式的实现: 能够根据配置文件生成ipvs规则,并对各RS的健康做检测:vrrp_script, vrrp_track: keepalive组件: 核心组件:(checkers vrrp stack ipvs wrapperwatch dog).IO复用器.内存管理.配置文件分析器 keepalive配置前提: 1.各

3.云计算基础知识

云计算基础知识 OSI七层模型 MAC/物理地址 MAC(Media Access Contro)地址,或称为MAC地址.物理地址,用来表示互联网上每一个站点的标识符,采用十六进制数表示,共六个字节(48位).其中,前三个学是由IEEE的注册管理机构RA负责给不同厂家分配的代码(高位24位),也称为编制上唯一的标识符"( Organizationally Unique Identifier),后三个字节(低位24位)由各厂家自行指派给生产的适配器接口,称为扩展标识符(唯一性).一个地址块可以生成

运维小白的成长日记第四天-基础网络构建OSI七层模型-物理层基础知识

运维小白的成长日记第四天- 基础网络构建OSI七层模型-物理层基础知识 网络运维的小白和想要加入网络运维的小伙伴们值得一看哦~ 今天是初识网络运维的第四天.希望能有志同道合的小伙伴一起讨论和学习,也希望有网络运维的大神能够帮忙在网络运维这条路上帮忙指点,能够多提意见使我进步. 今天和大家分享一下OSI七层模型中的物理层基础知识. 一.物理介质 1.传输数据的物理介质有:双绞线.光纤.同轴电缆(有线电视).无线.电力线.红外.蓝牙.微波 2.信号 (1)模拟信号:比如声波(水波纹) (2)数字信号

# 运维小白的成长日记第五天-# 基础网络构建OSI七层模型-数据链路层基础知识

运维小白的成长日记第五天- 基础网络构建OSI七层模型-数据链路层基础知识 网络运维的小白和想要加入网络运维的小伙伴们值得一看哦~今天是初识网络运维的第五天.希望能有志同道合的小伙伴一起讨论和学习,也希望有网络运维的大神能够帮忙在网络运维这条路上帮忙指点,能够多提意见使我进步. 今天和大家分享一下OSI七层模型中的数据链路层基础知识. 数据链路层1.以太网:我们平时接触的物理网络都是以太网.以CSMA/CD这种工作方式运行的网络.2.以太网工作原理:CSMA/CD,载波侦听多路访问/冲突检测.在

软件开发架构、网络基础知识、osi七层模型

一.软件开发的架构 涉及到两个程序之间通讯的应用大致可以分为两种: 第一种是应用类:qq.微信.网盘.优酷这一类是属于需要安装的桌面应用 第二种是web类:比如百度.知乎.博客园等使用浏览器访问就可以直接使用的应用 这些应用的本质其实都是两个程序之间的通讯.而这两个分类又对应了两个软件开发的架构 C/S架构: C/S即:Client与Server ,中文意思:客户端与服务器端架构,这种架构也是从用户层面(也可以是物理层面)来划分的. 这里的客户端一般泛指客户端应用程序EXE,程序需要先安装后,才