数据访问层中的业务对象


12

因此,我一直在通过TDD创建数据访问层,并且有些担心。我宁愿不走错误的道路,所以我想让你们看看我的想法是否符合干净的体系结构。

我的数据访问层(简称DAL)中的方法非常简单。它们与数据库中的存储过程一致(没有其他方法可以使数据库保持干净),并且它们包含与存储过程相同的参数。然后,他们仅连接到数据库,并返回查询结果。这是一个例子:

public int DeleteRecord(int recordId)
{
    recordId.RequireThat("recordId").NotZeroOrLess();

    List<SqlParameter> parameters = new List<SqlParameter>();
    parameters.Add(new SqlParameter { ParameterName = "@RecordId", SqlDbType = SqlDbType.Int, Direction = ParameterDirection.Input, Value = recordId});

    return this.ExecuteNonQuery("DeleteRecord", parameters.ToArray());
}

这对于这种类型的方法非常有效,因为我对结果集没有做任何有意义的事情。我只想确保命令有效,所以我将返回非查询的结果,该查询只是受影响的行,并且我可以使用该数字来验证逻辑。

但是,在另一种DAL方法中,我想加载一条记录。我的加载过程将selects针对一堆表执行并返回a DataSet,但是我正在努力解决DAL是否应该使用来在方法内创建Business Objects的问题DataSet或者我的Business Objects本身是否应该具有Load()获取该方法的方法的问题。DataSet然后从DAL开始,然后基本完成

通过DAL进行操作会导致业务对象中的逻辑更少(即使这只是选择逻辑,仍然是逻辑),但是会使DAL有点拥挤,使人感觉它确实在做它不应该做的事情。做。

你们有什么感想?


您为什么不使用实体框架?
jfrankcarr 2012年

@jfrankcarr-坦白地说,主要是因为我不应该对它熟悉。但是,我需要重新整理表并添加适当的外键等,以便实体框架能够正确识别关系。但是,出于好奇,如果我正在使用它,我是否将使用带有Business Objects本身的框架进行所有选择,还是仍然会决定将这些LINQ查询放在何处?

我建议花时间学习EF。乍一看似乎有些令人生畏,尤其是在尝试使其与存在一些预先存在的设计问题的现有数据库相适应时,但这是值得的。
jfrankcarr 2012年

如果您想研究另一个选项,也可以查看NHibernate。
唐01001100 2012年

@jfrankcarr-我肯定会研究它,但是它如何适合多层数据访问应用程序?实体框架本身会在DAL本身内还是在另一层甚至业务对象本身内实现?

Answers:


4

您的DAL应该返回您的数据对象

理想情况下,您的DAL应该是一个“黑匣子”对象,您的应用程序代码可将其用于请求数据对象或操纵现有数据对象。有时在DA​​L和应用程序代码之间还有另一层,称为Repository,这进一步分隔了两层,尽管并不总是需要这样做。

另外,您通常不希望业务对象能够创建自己。这可能会导致安全漏洞,.Load(someId)使其他人可以使用您的库,并通过调用它来创建对象的新实例,并且该对象将应该完全分开的两层合并在一起。

我也不建议提供一种.Load(DataSet ds)方法,因为如果数据集定义发生更改,则必须查找使用该数据集的数据对象并进行更改。将所有数据访问代码保存在一个地方更容易,因此,如果更改数据访问查询,则只需要更改DAL层即可。


如果“正确对象”的定义保留在另一层中,则不确定如何依赖一层来“返回正确对象”。
TMN 2012年

@TMN措辞不佳。我更改了措辞,因为您是对的,应用程序代码应知道其要求的对象类型。
雷切尔

@雷切尔-Gotcha。因此,您建议让DAL返回我的业务对象本身的实例,对吗?您对“数据对象”的措辞让我有些困惑,但我想我理解。这样,我的代码可以通过调用来从任何需要的地方请求业务对象(而不是通过它们本身),这BusinessObject bo = DAL.LoadRecord(id);听起来不错吗?将查询映射到BO本身的逻辑将包含在DAL中,并且仅包含在其中。

1
@Scott没错,尽管我将DAL方法命名为Get而不是Load,例如Customer c = DAL.GetCustomer(id);
Rachel

2

我的方法甚至在LINQ-To-SQL和Entity Framework之前,就是要有一个接口和抽象类库,该库为应用程序不同层之间的通信提供了“书面协定”。这有时称为本体,是工作域的定义。层之间传递的所有内容均使用此“合同”。

我不喜欢将原始Dataset对象从数据层传递到业​​务层的想法。我已经看到这会导致许多问题,尤其是在集成旧数据源时。对于新手来说,这也可能使新人很难理解数据的来源。最后,它要求您的业务层负责直接从数据库处理数据的业务,这可能会导致复杂的情况。

您使用的示例代码看起来与我在LINQ之前使用的代码相似。我在DAL对象中使用了一个通用的DB函数类。DAL类将读取数据并将其放入“合同”对象中。与删除示例一样,标量结果将返回一个值,通常为布尔值。


1
“我不喜欢将原始Dataset对象从数据层传递到业​​务层的想法。” 这个。一千次
约书亚·史密斯

@jfrankcarr-我的DAL实际上确实实现了一个接口,并且我确实计划为所有用于在层与层之间传输数据的事物都提供接口,因此我认为我们的模式思想与之匹配。因此,您是否建议我更改返回ExecuteScalar查询直接结果的方法,以返回对业务层更有意义的值,例如bool?我认为否则,这与雷切尔的答案非常相似。

我通常为创建/更新/删除调用返回一个布尔值,除非我需要受影响的记录数。例如,如果存储的proc正在处理多个订单行或类似的行,我可能会返回int。
jfrankcarr 2012年

0

您的DAL应该返回一个数据集。返回的数据集应该是商务对象,除了检查它是否具有预期的数据外,您不需要执行任何其他操作。如果您需要使用它做更多的事情,那么您要么尝试在单个存储过程中做太多事情,要么在存储过程中未正确返回数据。


0

我建议您的业务对象具有一个构造函数,以从结果集中填充自己。这消除了DAL与业务层之间的耦合。如果要完全隔离两者,请从结果集中创建一个列名=>值对的简单映射,然后将其传递给构造函数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.