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

如果你的程序分层清晰并且系统禁用复杂存储过程,那么在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. Java小应用程序Applet,画布上新建按钮和文本

    <pre name="code" class="java">package com.hx; import java.applet.*; import ...

  2. 1.一起来学hibernate之hibernate简介

    一.简介 Hibernate,是一个开源的ORM框架.所谓的ORM,即object relative mapping,就是对象关系映射. 那什么是对象关系映射? 对象,即java类,又称为实体类,对象 ...

  3. 命令行查看linux发行版版本信息

    有时候安装完自己的linux发行版系统(如ubuntu.centos.redhat.opensuse.--)时,把版本信息忽略了,又不想重启电脑,此时我们可以通过命令行方式来查看: 1.cat /et ...

  4. php乱码

    1:php 编码是utf-8 但是接口需要是gbk 这么办?? $message = "你的微点管理地址为:".$shortUrl." [请保存信息]"; // ...

  5. SQL Server 存储引擎-剖析Forwarded Records

    我们都知道数据在存储引擎中是以页的形式组织的,但数据页在不同的组织形式中其中对应的数据行存储是不尽相同的,这里通过实例为大家介绍下堆表的中特有的一种情形Forwared Records及处理方式. 概 ...

  6. 个性二维码开源专题<介绍篇>

    由C#编写的个性二维码底层,已应用到 码晒客/疯狂创意二维码等项目上,并获得多项软件著作专利. 疯狂创意二维码 疯狂创意二维码是可用于生成风格独特的个性化二维码生成器,用户可以将目标信息输入到二维码生 ...

  7. CodeIgniter nginx 404

    默认情况下CI 不支持路由模式需要在server里面配置,配置成如下即可: server { listen 80 ; server_name wechat.XX.com.cn; root XX; in ...

  8. 基于 IdentityServer3 实现 OAuth 2.0 授权服务数据持久化

    最近花了一点时间,阅读了IdentityServer的源码,大致了解项目整体的抽象思维.面向对象的重要性; 生产环境如果要使用 IdentityServer3 ,主要涉及授权服务,资源服务的部署负载的 ...

  9. 作业一:创建个人技术博客、自我介绍、简单的C程序

    年9月14日中午12点: 一.主要内容  建个人技术博客(博客园 www.cnblogs.com) 本学期将通过写博客的方式提交作业,实际上,最终的目的是希望同学们能通过博客的形式记录我们整个学习过程 ...

  10. JSP的那些事儿(2)---- DWR2.0 的配置和使用

    JSP的那些事儿(2)----DWR2.0 的配置和使用 分类: Web开发 JAVA 2009-04-23 15:43 999人阅读 评论(0) 收藏 举报 jspdwrjavascriptserv ...