DM层与Service层
首先分享一点自己最近的感悟:讨厌你的人总可以找到理由去讨厌你
正文开始
如果您是初次阅读这个系列,请先去《 Index & Writing Plan 》查找并阅读“ 架构设计系列” 的前两篇文章,顺序阅读会使您有更好的阅读体验
强烈推荐配合源代码阅读本文: 点击此处下载 (可以直接运行,会在本地自动生成数据库)
已经写完了Factory的实现。在Factory中,我们使用了预编译指令来实现了Model的切换:
#define A #if B using Model.B; using DBaccess.B; #endif #if A using Model.A; using DBaccess.A; #endif
切换Model,只需将#define A 修改为 #define B,非常方便(尽管要重新编译,还是让我有点不爽)
但是出现预编译指令的地方不宜过多——事实上,已经有一处要改就已经让我不爽了
所以,在DM层(数据操作层)与Service层(业务逻辑层)中,我们不能出现任何具体的Model的类名。
在本例中,就是DM和Service中不能出现类名:Teacher、Contact
因为每个出现了类Teacher和类Contact的地方,我们都要加上前文提到的预编译指令。而在实际项目中,这样做会导致切换Model要修改的地方非常多,可能会导致不可预期的错误
那么,DM层主要是用泛型来解决问题,代码如下:
public class DMbase
{
protected DbContext db;
public DMbase(DbContext db)
{
this .db = db;
}
/// <summary>
/// select one
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity"> 这里的entity并无实际作用,只是用于编译器推敲类型 </param>
/// <param name="predicate"> λ表达式 </param>
/// <returns> 返回第一条匹配的记录,若无记录返回null </returns>
public virtual T FindOne<T>(T entity, Func<T, bool > expression)
where T : class , new ()
{
return this .db.Set<T> ().FirstOrDefault(expression);
}
/// <summary>
/// select all
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity"> 这里的entity并无实际作用,只是用于编译器推敲类型 </param>
public virtual IQueryable<T> FindAll<T> (T entity)
where T : class , new ()
{
return this .db.Set<T> ();
}
public virtual void Insert<T>( params T[] entities)
where T : class , new ()
{
if (entities != null && entities.Length > 0 )
{
var set = this .db.Set<T> ();
foreach ( var item in entities)
{
set .Add(item);
}
}
}
public virtual void Delete<T>( params T[] entities)
where T : class , new ()
{
if (entities != null && entities.Length > 0 )
{
var set = this .db.Set<T> ();
foreach ( var item in entities)
{
set .Remove(item);
}
}
}
/// <summary>
/// 提交事务
/// </summary>
public void Commit()
{
this .db.SaveChanges();
}
}
我的注释也说明了,其实FindOne方法和FindAll方法其实是不需要参数的,但是为了编译器推敲类型,传入了一个entity参数
在此要感谢下 xanthodont 同学,这个DM是在你的版本上改的,封装得很不错
写完DM层,接下来就是重头戏,Service层
下面的代码示范了如何取得所有的Teacher,并将Teacher与Contact对应起来
public object FindAllTeacher()
{
// 取得一个Context
var context = ContextFactory.GetContext();
// 从Factory中取得Teacher和Contact
// 这里必须要用var
var a = ModelFactory.GetTeacher();
var b = ModelFactory.GetContact();
var aList = ModelListFactory.GetTeacherList();
DMbase dm = new DMbase(context);
// 用之前取得的Teacher与Contact传入DM层,方便编译器推敲类型
var contact = dm.FindAll(b);
var teacher = dm.FindAll(a);
// 业务逻辑,将Teacher与Contact关联起来
var result = teacher.Join(contact, o => o.ID, r => r.TeacherID, (o, r) => new { tt = o, aa = r });
result = result.OrderByDescending(o => o.aa.Email);
// 处理数据
foreach ( var item in result)
{
a = item.tt;
a.Contact = item.aa;
aList.Add(a);
}
return aList;
}
注意,这里我使用了Object作为返回类型 ,因为我其实不知道返回值是IList<Model.A.Teacher> 还是IList<Model.B.Teacher>,好在这里只需要一次拆装箱,无伤大雅
再来演示下如何插入:
public bool AddTeacher<T, T1> (T teacher, T1 contact)
where T : class , new ()
where T1 : class , new ()
{
try
{
var context = ContextFactory.GetContext();
DMbase dm = new DMbase(context);
dm.Insert(teacher);
dm.Insert(contact);
dm.Commit();
return true ;
}
catch
{
return false ;
}
}
只有执行了dm.Commit(),两个Insert才会提交到数据库,保证了事务的一致性
就此搁笔
PS:昨天是博主生日,又老了一岁;有缘读到这里的园友,就别吝啬自己的祝福了吧 :)
/*=============================================================*/
作者: CrazyJinn
本文版权归作者和博客园共有,欢迎转载.但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
如果看完这篇文章让您有所收获,请点击右下角"推荐".
如果这篇文章让您觉得不知所云,或者通篇谬误,请点击右下角"反对".并且欢迎您留言给我提出宝贵的意见.
如果您想获知我最新的动态,可以在绿色通道中点击"关注我".
/*=============================================================*/
分类: .NET
标签: 设计 , 架构
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息