将数据访问逻辑从业务层移至数据访问层
Posted
技术标签:
【中文标题】将数据访问逻辑从业务层移至数据访问层【英文标题】:Move Data Access logic from the business layer to the data access layer 【发布时间】:2012-07-06 03:55:55 【问题描述】:我正在做一个具有数据访问层 (DAL) 的 asp.net mvc 应用程序。 完成了 90% 的数据库 CRUD 代码后,我问自己是否需要业务层。
但是我应该放什么?例如,我在 DAL 中的所有 CRUD 方法都不是一个 sql 表上的单一选择。大多数时候我会做很多连接 + sql 聚合函数。顺便提一下,我使用 ADO.NET,没有存储过程/触发器。
然后我又问自己这样的方法是否属于业务层:
/// <summary>
/// Creates a testplan with all teststeps and their default values for a certain template
/// </summary>
/// <param name="testplan"></param>
/// <returns>true if transaction was successfull else false</returns>
public void CreateTestplan(Testplan testplan)
try
using (var con = new SqlConnection(_connectionString))
using (var trans = new TransactionScope())
con.Open();
_testplanDataProvider.AddTestplan(testplan,con);
_testplanDataProvider.CreateTeststepsForTestplan(testplan.Id, testplan.TemplateId,con);
trans.Complete();
catch (SqlException ex)
ExceptionManager.HandleException(ex);
这个方法实际上调用了 DAL 中的另外两个方法。
现在我问自己,为什么要引入一个额外的业务层,因为我可以将 CreateTestplan 方法也放在 TestplanDataProvider 类中,其中包含来自 AddTestplan + CreateTeststepsForTestplan 这两种方法的所有代码。
你怎么看?这是一个好方法吗?
我真的这么问是因为我认为 CreateTestplan 方法只包含数据访问逻辑。
更新:
public void AddTestplan(Testplan testplan, SqlConnection con)
using (var cmd = new SqlCommand("INSERT INTO TESTPLAN (ReleaseId,TemplateId,CreatedAt,UserId,Name,Duration) VALUES (@ReleaseId,@TemplateId,@CreatedAt,@UserId,@Name,@Duration);Select Scope_Identity();", con))
var p1 = new SqlParameter("@ReleaseId", testplan.ReleaseId);
var p2 = new SqlParameter("@TemplateId", testplan.TemplateId);
var p3 = new SqlParameter("@CreatedAt", testplan.CreatedAt);
var p4 = new SqlParameter("@UserId", testplan.UserId);
var p5 = new SqlParameter("@Name", testplan.Name);
var p6 = new SqlParameter("@Duration", testplan.Duration);
cmd.Parameters.AddRange(new[] p1, p2, p3, p4, p5, p6 );
testplan.Id = Convert.ToInt32(cmd.ExecuteScalar());
public void CreateTeststepsForTestplan(int testplanId, int templateId, SqlConnection con)
var teststeps = new List<Teststep>();
using (var selectCMD = new SqlCommand("SELECT ts.TeststepId, MAX(ts.CreatedAt)FROM Teststep ts INNER JOIN Unit u ON ts.UnitId = u.UnitId Where u.TemplateId = @TemplateId Group by TeststepId", con))
var p = new SqlParameter("@TemplateId", templateId);
selectCMD.Parameters.Add(p);
using (var reader = selectCMD.ExecuteReader())
Teststep teststep = null;
while (reader.Read())
teststep = new Teststep
Id = Convert.ToInt32(reader["TeststepId"]),
CreatedAt = Convert.ToDateTime(reader["CreatedAt"]),
;
teststeps.Add(teststep);
using (var insertCMD = new SqlCommand("INSERT INTO TestplanTeststep (TestplanId,TeststepId,TestState,ErrorText) VALUES (@TestplanId, @TeststepId, @TestState, @ErrorText)", con))
var p1 = new SqlParameter("@TeststepId", SqlDbType.Int);
var p2 = new SqlParameter("@CreatedAt", SqlDbType.DateTime);
var p3 = new SqlParameter("@TestplanId", testplanId);
var p4 = new SqlParameter("@ErrorText", DBNull.Value);
var p5 = new SqlParameter("@ErrorScreenshot", DBNull.Value);
var p6 = new SqlParameter("@TestState", (int)Teststep.TeststepTestState.Untested);
insertCMD.Parameters.AddRange(new[] p1, p2, p3, p4, p5 );
foreach (Teststep step in teststeps)
p1.Value = step.Id;
p2.Value = step.CreatedAt;
insertCMD.ExecuteNonQuery();
【问题讨论】:
【参考方案1】:不让 BLL 访问数据的一个很好的理由是,您可以切换数据库或数据库框架,而对业务逻辑的更改最少。
例如,如果您将所有与 ADO.NET 相关的代码移至 DAL,然后决定改用实体框架,则只有您的 DAL 会改变,而 BLL 不会改变。
当然,如果您的业务逻辑很少,并且您的 BLL 只是将工作交给您的 DAL,那么您可能不会从拥有单独的层中获益。对于非常琐碎的应用程序可能会出现这种情况,但它也可能表明您的 DAL 中隐藏了业务逻辑。
【讨论】:
我用来自 dataprovider 的代码示例更新了我的问题。你认为我在里面隐藏了业务逻辑? 我在这两种方法中看到的唯一内容是 ADO.NET 代码 - 没有业务逻辑。 对。因此,我将我的两个 dataprovider 方法再次移动到 ONE 方法中以直接调用它。不需要该服务。 我现在说你的说法是错误的:“我在那些中看到的唯一东西......”不存在业务逻辑。当我读到 Martin Fowler 的这篇文章时,我明白了这一点:martinfowler.com/articles/dblogic.html【参考方案2】:我知道普遍接受的最佳做法是将 DAC 与 BL 分开,但我的看法是,如果您使用 L2S 或实体框架之类的东西,您已经有一个 DAL,并且您的业务逻辑可以进入部分这些类的定义。无需在此之上添加另一个 DAL。我什至会认为 ADO 是构成 DAL 的抽象。顺便说一句,由于您使用的是海峡 ADO,您可能想看看 Dapper。这是一个最小且快速的 DAL。
【讨论】:
我只是在看 EF5 RC。几年前我尝试过 EF1,结果很糟糕。 是的。我使用了 linq to oracle 一段时间,然后我们切换到 linq to sql 。因为它与数据库无关,所以它很容易的前提是错误的。由于实现方式和数据库的不同,我们遇到了几个业务逻辑问题。归根结底,无论您怎么看,更改数据存储都是一件痛苦的事情。最好看看什么对你有用。我们现在正在迁移到 L2S 以插入、编辑、删除和编写我们相当复杂的选择语句作为视图,并使用 dapper 抓取它们以提高性能。 我们已经在 L2S 上,去年我尝试在其中编写一些实时报告的东西,对于超大型查询,遍历代码树的速度非常慢。多年前,我们最终选择了 L2 预言机。这是一家制药公司,所以甲骨文非常根深蒂固。我们应用程序的大部分内容都是专门为利用 linq 到 SQL 数据上下文内容而编写的。所以从 linq 到 oracle 再到 EF 似乎跳跃太大了。 好的。我讨厌 oracle ;-) 我们公司的每个人,尽管他们是我们做 BI 的基础,呵呵以上是关于将数据访问逻辑从业务层移至数据访问层的主要内容,如果未能解决你的问题,请参考以下文章
在单独的数据访问和业务逻辑层中,我可以在业务层中使用实体框架类吗?