一. 业务逻辑层的事务问题

如果你的程序分层清晰并且系统禁用复杂存储过程,那么在DA中的职责比较单一。程序的逻辑通过BLL调用各种不同模块的DA来实现数据操作。如果当需要不同模块在一个事务的时候,问题就产生了。

如果你在bll引用System.Data...或者你在DA中穿插各种复杂逻辑的时候基本上你的工程已经不能算是好的程序了,

1. 使用TransactionScope

TransactionScope可以使代码块成为事务性代码。但是需要开通MSDTC权限,并且TransactionScope的性能问题也一直存在争议。

2. 阶段性提交

这个涉及到框架层次的修改,会单独开篇幅来说

3. 使用委托 将多模块提交汇聚在一起 和框架层次的阶段性提交殊途同归

这个就是设计上的问题,将其他模块的方法以委托方式传入DA。举个例子假如主线为消费记录ConsumeRecord,分支线为消费详细ConsumeRecordDetail和票据信息TravelTicket。其中TravelTicket完全为另一个服务模块对自己为黑盒。ConsumeRecordDetail对自己为白盒。

  DA层

     public delegate BizResult<string> ArchiveTravelTicketDelegate( DbTransaction transaction, List<string> travelTicketIDList);

  主线服务BLL中,其中StartArchives为其他模块但是需要包含近事务的方法

        private BizResult<string> InsertConsumeRecord(ConsumeRecordEntity consumeRecordEntity, List<ConsumeRecordDetailEntity> consumeRecordDetails)
{
return consumeRecordArchiveTargetDA.DoArchive(consumeRecordEntity, consumeRecordDetails, new TravelTicketArchiveService().StartArchives);
}

  主线服务DA中

     public BizResult<string> DoArchive(ConsumeRecordEntity consumeRecordEntity, List<ConsumeRecordDetailEntity> consumeRecordDetails, 
ArchiveHelper.ArchiveTravelTicketDelegate archiveTravelTicket)
{
return ArchiveHandle(consumeRecordEntity, consumeRecordDetails, true, ConsumeRecordHandle, archiveTravelTicket);
}
        public BizResult<string> ConsumeRecordHandle(DbTransaction currentTransaction, ConsumeRecordEntity consumeRecordEntity, List<ConsumeRecordDetailEntity> consumeRecordDetails)
{
return ConsumeRecordHandle(currentTransaction, consumeRecordEntity, consumeRecordDetails,
(x, y) => InsertConsumeRecordLog(currentTransaction, consumeRecordEntity, true, false)
, InsertConsumeRecord, consumeRecordDetailArchiveDA.InsertConsumeRecordDetail);
}

  其中InsertConsumeRecordLog,InsertConsumeRecord为主线自己的方法,ConsumeRecordDetail因为白盒可以直接使用consumeRecordDetailArchiveDA.InsertConsumeRecordDetail,archiveTravelTicket为黑盒。

   主线BaseDA中

     public BizResult<string> ArchiveHandle(ConsumeRecordEntity consumeRecordEntity, List<ConsumeRecordDetailEntity> consumeRecordDetails, bool isArchive,
ConsumeRecordHandlerDelegate consumeRecordHandlerDelegate, ArchiveHelper.ArchiveTravelTicketDelegate archiveTravelTicket)
{
using (DbConnection dbConnection = DbObject.CreateConnection())
{
dbConnection.Open(); BizResult<string> bizResult;
using (DbTransaction currentTransaction = dbConnection.BeginTransaction())
{
try
{
bizResult = consumeRecordHandlerDelegate(currentTransaction, consumeRecordEntity, consumeRecordDetails);
if (bizResult.IsSuccessful)
{
if (archiveTravelTicket != null)
{
bizResult = archiveTravelTicket(currentTransaction,
consumeRecordDetails.Select(x => x.TravelMoneyID).
Distinct().ToList());
}
if (bizResult.IsSuccessful)
{
bizResult.Message = "xxx success";
currentTransaction.Commit();
return bizResult;
}
bizResult.Message = "xxx fail";
}
bizResult.Message = string.Format("{0}:{1}", isArchive, bizResult.Message);
currentTransaction.Rollback();
}
catch (Exception ex)
{
logger.Error(ex);
currentTransaction.Rollback();
throw;
}
}
return bizResult;
}
}

二. 测试环节的page object模式

  拿自动化测试Selenium为例,一般而言我们对于程序都是应付测试用例,针对测试用例写出一个一个test-method。这样无可厚非,使用page object模式可以让代码开起来更专业更精彩。

  在自动化测试中,主要关注UI的测试互动区域。 Page对象只是这些模型作为测试代码中的对象可以减少了重复的代码量,并且意味着,如果用户界面的变化,也只需要修改一个地方。和软件设计模式中dry(don't repeat yourself)类似。并且在page object模式中,PageObjects也可以实现页于页之间的逻辑。总得来说减少了代码的重复,让测试更具可读性和强大的,提高了测试的可维护性,特别是当有频繁变化的ui变更。

举个列子(java版本)

public class LoginPageTest {
private LoginPage loginPage;
private final String username = "xx@163.com";
private final String pwd= "Welcome1"; @Before
public void setUp() throws Exception {
String applicationRoot = new File(
getClass().getProtectionDomain().getCodeSource().getLocation().getPath())
.getParent();
System.setProperty("webdriver.chrome.driver", applicationRoot + "/chromedriver");
WebDriver webDriver = new ChromeDriver();
loginPage = new LoginPage(webDriver);
loginPage.init();
} @Test
public void testLoginWithoutFakeCheckbox()
{
loginPage.setUserName(username);
loginPage.setPassword(pwd);
loginPage.pressLoginButton();
assertThat(loginPage.getClassByLoginWithoutFakeCheckbox(), equalTo("checkbox-wrapper not-checked"));
} @Test
public void testLoginWithWrongUsername()
{
loginPage.setUserName("wrongusername");
loginPage.setPassword(pwd);
loginPage.pressCheckBox();
loginPage.pressLoginButton();
assertThat(loginPage.getClassByLoginWithWrongUserName(), equalTo("wrapper-input-text wrong"));
} @Test
public void testLoginWithNullPwd()
{
loginPage.clearInput();
loginPage.setUserName(username);
loginPage.pressCheckBox();
loginPage.pressLoginButton();
assertThat(loginPage.getClassByLoginWithNullPwd(), equalTo("wrapper-input-text wrong"));
} @Test
public void testLoginWithRightWay()
{
loginPage.clearInput();
loginPage.setUserName(username);
loginPage.setPassword(pwd);
loginPage.pressCheckBox();
loginPage.pressLoginButton();
assertThat(loginPage.getTextByRightWay(), equalTo("选择性别"));
} }

  

public class LoginPage {
private final WebDriver webDriver;
private final WebDriverWait wait;
private JavascriptExecutor js;
private final String username = "xx@163.com";
private final String pwd = "Welcome1";
private WebElement webElementLogin;
private WebElement webElementPwd;
private WebElement webElementInput; public LoginPage(WebDriver webDriver) {
this.webDriver = webDriver;
this.wait = new WebDriverWait(webDriver, 10);
this.js = (JavascriptExecutor) webDriver;
} public void init() {
webDriver.get("http://root:root@localhost:8080/apitool/xxx/owF3PjkBFY5_56Q_KYs5fxmLZTKI");
WebElement webElementName = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("p.text.bold.name"))); if (webElementName != null) {
System.out.print(webElementName.getText());
}
webElementLogin = webDriver.findElement(By.cssSelector("input.input-text.login-input"));
webElementLogin.sendKeys(username);
webElementPwd = webDriver.findElement(By.cssSelector("input.input-text.password-input"));
webElementPwd.sendKeys(pwd);
} public String getClassByLoginWithoutFakeCheckbox() {
WebElement webElementCss = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.xpath("//*[contains(@class,'checkbox-wrapper not-checked')]")));
WebElement webElementHref = webDriver.findElement(By.xpath("//*[@id=\"login-page\"]/div/section/div/div[5]/div/div"));
return webElementHref.getAttribute("class");
} public String getClassByLoginWithWrongUserName() {
webElementInput = webDriver.findElement(By.xpath("//*[@id=\"login-page\"]/div/section/div/div[3]"));
return webElementInput.getAttribute("class");
} public String getClassByLoginWithNullPwd() {
webElementInput = webDriver.findElement(By.xpath("//*[@id=\"login-page\"]/div/section/div/div[3]"));
return webElementInput.getAttribute("class");
} public String getTextByRightWay() {
GenderViewPage genderViewPage = new GenderViewPage(webDriver);
return genderViewPage.getGenderText();
} public void pressCheckBox() {
js.executeScript("$('.fake-checkbox').attr('class','fake-checkbox active')");
} public void clearInput() {
webElementLogin.clear();
webElementPwd.clear();
} public void setUserName(String username) {
webElementLogin.clear();
webElementLogin.sendKeys(username); } public void setPassword(String password) {
webElementPwd.clear();
webElementPwd.sendKeys(pwd);
} public void pressLoginButton() {
js.executeScript("$('.login-button').trigger('touchstart')");
} public void closeBrowser()
{
webDriver.quit();
}
}

三. sql update 慎用位运算

update t_User set valye = Flag | 4 where UserID = 1

如果Flag字段中存在负数,在做位运算的时候,更新出非常大的数值,超过2的62次方

希望对大家有帮助。

【C#|.NET】从细节出发(三) 逻辑层事务和page object模式的更多相关文章

  1. 从零开始编写自己的C#框架(14)——T4模板在逻辑层中的应用(三)

    原本关于T4模板原想分5个章节详细解说的,不过因为最近比较忙,也不想将整个系列时间拉得太长,所以就将它们整合在一块了,可能会有很多细节没有讲到,希望大家自己对着代码与模板去研究. 本章代码量会比较大, ...

  2. [Prodinner项目]学习分享_第三部分_Service层(业务逻辑层)

    前两节讲到怎样生成一个Model和怎样将Model映射到数据库,这一节将讲到业务逻辑层,也就是Service层. 1.Prodinner架构已经构建好的,基本的增删改查. 假设,我现在想操作第二节中讲 ...

  3. 微信小程序学习笔记(三)--框架-逻辑层

    逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈. 开发者写的所有代码最终将会打包成一份 JavaScript 文件,并在小程序启动的时候运行,直到小程序销毁.这一行为类似 Service ...

  4. MVC5 网站开发之四 业务逻辑层的架构和基本功能

    业务逻辑层在Ninesky.Core中实现,主要功能封装一些方法通过调用数据存储层,向界面层提供服务.   目录 奔跑吧,代码小哥! MVC5网站开发之一 总体概述 MVC5 网站开发之二 创建项目 ...

  5. 从零开始编写自己的C#框架(12)——T4模板在逻辑层中的应用(一)(附源码)

    对于T4模板很多朋友都不太熟悉,它在项目开发中,会帮我们减轻很大的工作量,提升我们的开发效率,减少出错概率.所以学好T4模板的应用,对于开发人员来说是非常重要的. 园子里对于T4模板的介绍与资料已经太 ...

  6. C#多态“说来也说”——逻辑层BLL中的多态使用

    本文版权归博客园和作者吴双本人共同所有.欢迎转载,转载和爬虫请注明原文地址 http://www.cnblogs.com/tdws/p/5861842.html 昨天晚上,有个朋友说学了好久,依然没搞 ...

  7. 9.1.3 .net framework通过业务逻辑层自动生成WebApi的做法

    首先需要说明的是这是.net framework的一个组件,而不是针对.net core的.目前工作比较忙,因此.net core的转换正在编写过程中,有了实现会第一时间贴出来. 接下来进入正题.对于 ...

  8. HL AsySocket 服务开发框架 - 业务逻辑层

    一 概述 Socket服务只是提供一个网络传输服务. 业务逻辑层在整体架构中的位置在那里呢,如图: 网络层将解包后的消息包抛至业务逻辑层,业务逻辑层收到消息包后,解析消息类型,然后转入相应的处理流程处 ...

  9. JSP业务逻辑层

    经典的三层架构:表示层.业务逻辑层和数据访问层 具体的区分方法 1:数据访问层:主要看你的数据层里面有没有包含逻辑处理,实际上他的各个函数主要完成各个对数据文件的操作.而不必管其他操作. 2:业务逻辑 ...

随机推荐

  1. hdu - 3959 Board Game Dice(数学)

    这道题比赛中没做出来,赛后搞了好久才出来的,严重暴露的我薄弱的数学功底, 这道题要推公式的,,,有类似于1*a+2*a^2+3*a^3+...+n*a^n的数列求和. 最后画了一张纸才把最后的结果推出 ...

  2. Mac中brew的安装

    brew是Mac OS的一个软件包管理工具,使用简单方便,就像ubuntu中的apt-get命令一样官方地址:http://brew.sh/index_zh-cn.html 终端下运行 /usr/bi ...

  3. jsf2.0 tomcat 修改页面后无法立马看到页面修改效果

    转载于  http://stackoverflow.com/questions/12203657/jsf2-myfaces-xhtml-modifications-do-not-affect-unti ...

  4. Request Tracker 4.0.13 发布

    Request Tracker 4.0.13 修复了几个重要的安全问题. Request Tracker,企业级的问题跟踪系统

  5. Dynamic CRM 2013学习笔记(四十三)流程6 - 自定义流程活动

    当我们在流程里添加步骤时,有一些默认的步骤,像创建.更新.发邮件等,但如果你想加一个里面没有的步骤,比如发SMS消息,或者调用一个外部的web service,怎么办?这时就只能自定义一个流程活动了. ...

  6. django rest_framework

    环境 django 1.6,rest_framework 3.3 ubuntu采用pip安装的rest_framework 按照例子一步步做下来 运行 提示filters.py第119行有错误form ...

  7. Google 镜像站搜集[转]

    Google 镜像站搜集 原文链接:http://www.itechzero.com/google-mirror-sites-collect.html 如果您是以下镜像的作者,并且不希望您的镜像出现在 ...

  8. Win10年度更新开发必备:VS2015 Update 3正式版下载汇总

    微软在06月27日发布了Visual Studio 2015 Update 3 .在MSDN中微软也提供下载,而且MSDN的Visual Studio 2015 Update 3与官方免费下载的文件是 ...

  9. 浅谈压缩感知(二十五):压缩感知重构算法之分段正交匹配追踪(StOMP)

    主要内容: StOMP的算法流程 StOMP的MATLAB实现 一维信号的实验与结果 门限参数Ts.测量数M与重构成功概率关系的实验与结果 一.StOMP的算法流程 分段正交匹配追踪(Stagewis ...

  10. paip.提升性能----数据库连接池以及线程池以及对象池

    paip.提升性能----数据库连接池以及线程池以及对象池 目录:数据库连接池c3po,线程池ExecutorService:Jakartacommons-pool对象池 作者Attilax  艾龙, ...