在上篇随笔《Entity Framework 实体框架的形成之旅--数据传输模型DTO和实体模型Entity的分离与联合》里面,介绍了在Entity Framework 实体框架里面引入了DTO的对象,通过数据传输模型DTO和实体模型Entity的分离与联合,很好的隔离了它们的关系,使得即使是复杂的实体模型Entity,也不会影响WCF接口数据的传输和处理。本文主要介绍在基于这个分离模型的基础上,如何在界面实现多种常规的处理操作。

1、常规业务的增加、更新操作

对于业务对象的增加,由于我们引入了DTO对象,因此在界面的处理端,肯定也是利用了DTO对象进行的,如下代码是增加、修改的处理操作处理。

       public bool SaveAddNew()
{
DictDataInfo info = new DictDataInfo();
SetInfo(info); try
{
bool succeed = CallerFactory<IDictDataService>.Instance.Insert(info);
if (succeed)
{
int intSeq = ;
string seqValue = this.txtSeq.Text;
if (int.TryParse(seqValue, out intSeq))
{
this.txtSeq.Text = (intSeq + ).ToString().PadLeft(seqValue.Trim().Length, '');
}
this.txtName.Focus();
this.txtName.SelectAll();
}
return succeed;
}
catch (Exception ex)
{
LogTextHelper.Error(ex);
MessageDxUtil.ShowError(ex.Message);
}
return false;
} public override bool SaveUpdated()
{
DictDataInfo info = CallerFactory<IDictDataService>.Instance.FindByID(ID); if (info != null)
{
SetInfo(info); try
{
bool succeed = CallerFactory<IDictDataService>.Instance.Update(info, info.ID.ToString());
return succeed;
}
catch (Exception ex)
{
LogTextHelper.Error(ex);
MessageDxUtil.ShowError(ex.Message);
}
} return false;
}

上面的操作,和我之前的混合框架的使用代码是差不多的,原来的基于EnterpriseLibrary架构的框架,实体类采用的就是 "表名+Info" 的方式,虽然这里的**Info代表DTO对象,是实体框架的Entity对象的映射类,不过总体业务上的处理代码是差不多的了,这也是我希望看到比较平滑过渡和容易理解的改变之一。

2、基于DTO表达式的查询处理

如果对于查询,我们知道,如果使用字符串的条件表达式,一般也是可以实现处理操作的,不过就是需要硬编码SQL语句,对于一些安全性高一点的处理,可能不太好,由于实体框架可以采用Lamda表达式来进行查询,那么我们是否也可以在界面采用Lamda表达式来替代条件的SQL语句呢?

我们知道,上篇随笔已经介绍了引入DTO对象,用来解耦实体框架的对象模型,如下所示的模块分层场景。

这样我们在设计BLL业务逻辑层的时候,肯定还是可以使用实体框架的Expression<Func<T, bool>>表达式的,如IBLL层的接口定义对于Expression表达式的使用接口如下所示。

        /// <summary>
/// 根据条件查询数据库,并返回对象集合
/// </summary>
/// <param name="match">条件表达式</param>
/// <returns></returns>
IList<T> Find(Expression<Func<T, bool>> match); /// <summary>
/// 根据条件表达式返回可查询的记录源
/// </summary>
/// <param name="match">查询条件</param>
/// <param name="sortPropertyName">排序属性名称</param>
/// <param name="isDescending">如果为true则为降序,否则为升序</param>
/// <returns></returns>
IQueryable<T> GetQueryable(Expression<Func<T, bool>> match, string sortPropertyName, bool isDescending = true);

不过在门面层Facade层就不能继续使用了这种Expression<Func<T, bool>>表达式的了,同时也不能在Facade层使用IQueryable<T>接口,因为WCF服务无法序列化这个接口的。

那基于这个原因,我们应该如何传递Expression<Func<T, bool>> match这个条件参数的表达式呢,答案是引入Serialize.Linq组件,使用ExpressionNode对象进行承载,最后再把它解析为Expression<Func<T, bool>> match进行处理就可以了。

        /// <summary>
/// 根据条件查询数据库,并返回对象集合
/// </summary>
/// <param name="match">条件表达式</param>
/// <returns></returns>
[OperationContract(Name = "Find")]
IList<DTO> Find(ExpressionNode match); /// <summary>
/// 根据条件查询数据库,并返回对象集合(异步)
/// </summary>
/// <param name="match">条件表达式</param>
/// <returns></returns>
[OperationContract(Name = "FindAsync")]
Task<IList<DTO>> FindAsync(ExpressionNode match);

我们在客户端界面里面处理的话,就需要构建一个ExpressionNode对象,查询处理代码如下所示。

这里主要需要先从Expression<Function<T,boo>>到ExpressionNode,通过调用expression.ToExpressionNode();进行处理得到,如下代码所示。

        private ExpressionNode GetCondtionSql()
{
Expression<Func<DictDataInfo, bool>> expression = p => p.DictType_ID == this.lblDictType.Tag.ToString();
var queryNode = expression.ToExpressionNode();
return queryNode;
} private void BindData()
{
#region 添加别名解析
this.winGridViewPager1.DisplayColumns = "Name,Value,Seq,Remark,EditTime";
this.winGridViewPager1.AddColumnAlias("ID", "编号");
this.winGridViewPager1.AddColumnAlias("DictType_ID", "字典大类");
this.winGridViewPager1.AddColumnAlias("Name", "项目名称");
this.winGridViewPager1.AddColumnAlias("Value", "项目值");
this.winGridViewPager1.AddColumnAlias("Seq", "字典排序");
this.winGridViewPager1.AddColumnAlias("Remark", "备注");
this.winGridViewPager1.AddColumnAlias("Editor", "修改用户");
this.winGridViewPager1.AddColumnAlias("EditTime", "更新日期");
#endregion if (this.lblDictType.Tag != null)
{
ExpressionNode condition = GetCondtionSql();
WHC.Pager.Entity.PagerInfo pagerInfo = this.winGridViewPager1.PagerInfo;
IList<DictDataInfo> list = CallerFactory<IDictDataService>.Instance.FindWithPager(condition, ref pagerInfo);
//this.winGridViewPager1.PagerInfo.RecordCount = pagerInfo.RecordCount;
this.winGridViewPager1.DataSource = new WHC.Pager.WinControl.SortableBindingList<DictDataInfo>(list);
}
}

我们在Facade接口实现端,就需要把ExpressionNode反过来变成Expression<Function<T,boo>>对象。

        /// <summary>
/// 根据条件查询数据库,并返回对象集合
/// </summary>
/// <param name="match">条件表达式</param>
/// <returns></returns>
public virtual IList<DTO> Find(ExpressionNode match)
{
Expression<Func<Entity, bool>> mappedSelector = ConvertExpression(match); IList<Entity> tList = baseBLL.Find(mappedSelector);
return tList.MapToList<Entity, DTO>();
} /// <summary>
/// 根据条件查询数据库,并返回对象集合(异步)
/// </summary>
/// <param name="match">条件表达式</param>
/// <returns></returns>
public virtual async Task<IList<DTO>> FindAsync(ExpressionNode match)
{
Expression<Func<Entity, bool>> mappedSelector = ConvertExpression(match); IList<Entity> tList = await baseBLL.FindAsync(mappedSelector); IList<DTO> collection = tList.MapToList<Entity, DTO>();
return await Task<IList<DTO>>.FromResult(collection);
}

这样我们就可以很好利用Entity Framework 实体框架的LINQ表达式进行查询了。

3、多条件的处理方式

上面的查询代码里面,我们注意到了,条件里面只有一个条件,如下代码。

        private ExpressionNode GetCondtionSql()
{
Expression<Func<DictDataInfo, bool>> expression = p => p.DictType_ID == this.lblDictType.Tag.ToString();
var queryNode = expression.ToExpressionNode();
return queryNode;
}

那么对于有多个条件的话,处理就需要特殊处理了,否则就没法组合多个条件进行查询了,多个条件的处理是如何的呢?

如对于日志查询界面来说,如果是采用条件语句的方式,需要使用下面的代码组装语句,然后通过接口方法进行获取数据。

        /// <summary>
/// 根据查询条件构造查询语句
/// </summary>
private string GetConditionSql()
{
SearchCondition condition = new SearchCondition();
condition.AddCondition("LoginName", this.txtLoginName.Text, SqlOperator.Like);
condition.AddCondition("FullName", this.txtRealName.Text, SqlOperator.Like);
condition.AddCondition("Note", this.txtNote.Text, SqlOperator.Like);
condition.AddCondition("IPAddress", this.txtIPAddress.Text, SqlOperator.Like);
condition.AddCondition("MacAddress", this.txtMacAddress.Text, SqlOperator.Like); if (dateTimePicker1.Text.Length > )
{
condition.AddCondition("LastUpdated", Convert.ToDateTime(dateTimePicker1.DateTime.ToString("yyyy-MM-dd")), SqlOperator.MoreThanOrEqual);
}
if (dateTimePicker2.Text.Length > )
{
condition.AddCondition("LastUpdated", Convert.ToDateTime(dateTimePicker2.DateTime.AddDays().ToString("yyyy-MM-dd")), SqlOperator.LessThanOrEqual);
} string systemType = this.txtSystemType.GetComboBoxValue();
if (!string.IsNullOrEmpty(systemType))
{
condition.AddCondition("SystemType_ID", systemType, SqlOperator.Equal);
} //如果是公司管理员,增加公司标识
if (Portal.gc.UserInRole(RoleInfo.CompanyAdminName))
{
condition.AddCondition("Company_ID", Portal.gc.UserInfo.Company_ID, SqlOperator.Equal);
} string where = condition.BuildConditionSql().Replace("Where", "");
//如果是单击节点得到的条件,则使用树列表的,否则使用查询条件的
if (!string.IsNullOrEmpty(treeConditionSql))
{
where = treeConditionSql;
}
return where;
}

这里有很多条件,通过 SearchCondition 对象,我们能够很方便组合多个条件的查询,然后生成所需的条件语句就可以了,那么对于实体框架里面,我们需要采用Lamda表达式的话,应该如何构建对象并传入给接口方法呢,代码如下所示。

        /// <summary>
/// 根据查询条件构造查询语句
/// </summary>
private ExpressionNode GetConditionSql()
{
Expression<Func<LoginLogInfo, bool>> expression = p => true;
if (!string.IsNullOrEmpty(this.txtLoginName.Text))
{
expression = expression.And(x => x.LoginName.Contains(this.txtLoginName.Text));
}
if (!string.IsNullOrEmpty(this.txtRealName.Text))
{
expression = expression.And(x => x.FullName.Contains(this.txtRealName.Text));
}
if (!string.IsNullOrEmpty(this.txtNote.Text))
{
expression = expression.And(x => x.Note.Contains(this.txtNote.Text));
}
if (!string.IsNullOrEmpty(this.txtIPAddress.Text))
{
expression = expression.And(x => x.IPAddress.Contains(this.txtIPAddress.Text));
}
if (!string.IsNullOrEmpty(this.txtMacAddress.Text))
{
expression = expression.And(x => x.MacAddress.Contains(this.txtMacAddress.Text));
} if (dateTimePicker1.Text.Length > )
{
expression = expression.And(x => x.LastUpdated >= Convert.ToDateTime(dateTimePicker1.DateTime.ToString("yyyy-MM-dd")));
}
if (dateTimePicker2.Text.Length > )
{
expression = expression.And(x => x.LastUpdated <= Convert.ToDateTime(dateTimePicker2.DateTime.AddDays().ToString("yyyy-MM-dd")));
} string systemType = this.txtSystemType.GetComboBoxValue();
if (!string.IsNullOrEmpty(systemType))
{
expression = expression.And(x => x.SystemType_ID == systemType);
} //如果是公司管理员,增加公司标识
if (Portal.gc.UserInRole(RoleInfo.CompanyAdminName))
{
expression = expression.And(x => x.Company_ID == Portal.gc.UserInfo.Company_ID);
} //如果是单击节点得到的条件,则使用树列表的,否则使用查询条件的
if (treeCondition != null)
{
expression = treeCondition;
}
return expression.ToExpressionNode();
}

这里我们注意到expression.And或者expression.Or函数,它不是这个expression对象的方法的,是我们针对这个做的一个扩展类函数,它专门处理 Lamda-Expression表达式的扩展,方便组合多个条件,如两个表达式条件可以组合为AND或者OR条件方式。

这样我们在界面处理的时候,绑定数据的处理方法就可以如下所示了。

        public void BindData()
{
#region 添加别名解析
this.winGridViewPager1.DisplayColumns = "ID,User_ID,LoginName,FullName,Company_ID,CompanyName,Note,IPAddress,MacAddress,SystemType_ID,LastUpdated";
this.winGridViewPager1.ColumnNameAlias = CallerFactory<ILoginLogService>.Instance.GetColumnNameAlias();//字段列显示名称转义 #endregion ExpressionNode where = GetConditionSql();
PagerInfo PagerInfo = this.winGridViewPager1.PagerInfo;
IList<LoginLogInfo> list = CallerFactory<ILoginLogService>.Instance.FindWithPager(where, ref PagerInfo);
this.winGridViewPager1.DataSource = new WHC.Pager.WinControl.SortableBindingList<LoginLogInfo>(list);
}

以上就是我对于混合型的Entity Framework 实体框架的界面操作,总结的几种分析场景,希望对大家理解在WCF模式里面,使用实体框架的方法有所帮助。

这个系列文章如下所示:

Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)

Entity Framework 实体框架的形成之旅--利用Unity对象依赖注入优化实体框架(2)

Entity Framework 实体框架的形成之旅--基类接口的统一和异步操作的实现(3)

Entity Framework 实体框架的形成之旅--实体数据模型 (EDM)的处理(4)

Entity Framework 实体框架的形成之旅--Code First的框架设计(5)

Entity Framework 实体框架的形成之旅--Code First模式中使用 Fluent API 配置(6)

Entity Framework 实体框架的形成之旅--数据传输模型DTO和实体模型Entity的分离与联合

Entity Framework 实体框架的形成之旅--界面操作的几个典型的处理(8)

Entity Framework 实体框架的形成之旅--界面操作的几个典型的处理(8)的更多相关文章

  1. Entity Framework 实体框架的形成之旅--几种数据库操作的代码介绍(9)

    本篇主要对常规数据操作的处理和实体框架的处理代码进行对比,以便更容易学习理解实体框架里面,对各种数据库处理技巧,本篇介绍几种数据库操作的代码,包括写入中间表操作.联合中间表获取对象集合.递归操作.设置 ...

  2. Entity Framework 实体框架的形成之旅--实体数据模型 (EDM)的处理(4)

    在前面几篇关于Entity Framework 实体框架的介绍里面,已经逐步对整个框架进行了一步步的演化,以期达到统一.高效.可重用性等目的,本文继续探讨基于泛型的仓储模式实体框架方面的改进优化,使我 ...

  3. Entity Framework 实体框架的形成之旅--实体框架的开发的几个经验总结

    在前阵子,我对实体框架进行了一定的研究,然后把整个学习的过程开了一个系列,以逐步深入的方式解读实体框架的相关技术,期间每每碰到一些新的问题需要潜入研究.本文继续前面的主题介绍,着重从整体性的来总结一下 ...

  4. Entity Framework 实体框架的形成之旅--为基础类库接口增加单元测试,对基类接口进行正确性校验(10)

    本篇介绍Entity Framework 实体框架的文章已经到了第十篇了,对实体框架的各个分层以及基类的封装管理,已经臻于完善,为了方便对基类接口的正确性校验,以及方便对以后完善或扩展接口进行回归测试 ...

  5. Entity Framework 实体框架的形成之旅--数据传输模型DTO和实体模型Entity的分离与联合

    在使用Entity Framework 实体框架的时候,我们大多数时候操作的都是实体模型Entity,这个和数据库操作上下文结合,可以利用LINQ等各种方便手段,实现起来非常方便,一切看起来很美好.但 ...

  6. Entity Framework 实体框架的形成之旅--Code First模式中使用 Fluent API 配置(6)

    在前面的随笔<Entity Framework 实体框架的形成之旅--Code First的框架设计(5)>里介绍了基于Code First模式的实体框架的经验,这种方式自动处理出来的模式 ...

  7. Entity Framework 实体框架的形成之旅--Code First的框架设计(5)

    在前面几篇介绍了Entity Framework 实体框架的形成过程,整体框架主要是基于Database First的方式构建,也就是利用EDMX文件的映射关系,构建表与表之间的关系,这种模式弹性好, ...

  8. Entity Framework 实体框架的形成之旅--基类接口的统一和异步操作的实现(3)

    在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建 ...

  9. Entity Framework 实体框架的形成之旅--利用Unity对象依赖注入优化实体框架(2)

    在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建 ...

随机推荐

  1. VS开发中的代码编写小技巧——避免重复代码编写的几种方法

    上一篇文章中程序员的幸福生活--有你的日子,每天都是情人节,收到了大家的很多好评.鼓励和祝福,非常感动,真诚的谢谢大家.也希望每个朋友都能保持一个积极向上的心态,去迎接丰富多彩的人生. 在开发过程中, ...

  2. 如何用django开发一个简易个人Blog

    功能概要:(目前已实现功能) 公共展示部分: 1.网站首页展示已发布的博客记录,包括名称.摘要信息.发布日期.阅读量及评论数. 2.首页文章列表可按照分类筛选. 3.点击标题或阅读全文链接,进入博客阅 ...

  3. Atitit  ocr识别原理 与概论 attilax总结

    Atitit  ocr识别原理 与概论 attilax总结 1.1. Ocr的过程与流程1 1.2. OCR不同技术细分略有不同,但大概原理是一样的. 即主要技术过程是:二值化(又叫归一化)----- ...

  4. html5 响应式布局

    一.什么是响应式布局?       响应式布局是Ethan Marcotte在2010年5月份提出的一个概念,简而言之,就是一个网站能够兼容多个终端——而不是为每个终端做一个特定的版本. 这个概念是为 ...

  5. hadoop安装遇到的各种异常及解决办法

    hadoop安装遇到的各种异常及解决办法 异常一: 2014-03-13 11:10:23,665 INFO org.apache.hadoop.ipc.Client: Retrying connec ...

  6. 学习bootstrap遇到的问题--001 关于bootstrap中类.disabled不禁用默认行为

    自学bootstrap遇到的疑惑篇: 按钮状态--禁用 在Bootstrap框架中,要禁用按钮有两种实现方式: 方法1:在标签中添加disabled属性 方法2:在元素标签中添加类名"dis ...

  7. 自引用指针this

    C++为成员函数提供了一个名字为this的指针,这个指针称为自引用指针,每当创建一个对象时,系统就把this指针初始化为指向该对象,即this指针的值是当前调用成员函数的对象的起始地址.每当调用一个成 ...

  8. windows下zookeeper伪集群搭建

    下载 http://www.apache.org/dyn/closer.cgi/zookeeper/ 解压 D:\Java\soft\zookeeper-3.4.6 伪集群 1.在 \zookeepe ...

  9. Locations Section of OpenCascade BRep

    Locations Section of OpenCascade BRep eryar@163.com 摘要Abstract:本文结合OpenCascade的BRep格式描述文档和源程序,对BRep格 ...

  10. Android实现下滑和上滑事件

    做过开发的对于下滑刷新与上滑加载都一定不陌生,因为我们在很多时候都会使用到,那对对于这个效果如何实现呢?相信难道过很多小伙伴,今天我就带领大家一道通过第三方组件快速完成上述效果的实现,保准每位小伙伴都 ...