我有一个关于如何正确地将数据访问层中从数据库获得的值分配给WCF层的数据契约的问题。
考虑一个简单的场景,从数据库中获取所有学生的列表,然后将其分配给学生数据契约。
我的学生数据合同如下:
[DataContract]
public class StudentDC
{
[DataMember]
public int StudentID { get; set; }
[DataMember]
public string StudentName { get; set; }
}
在我的数据访问类中,我将有一个方法,如List GetAllStudents()
我的问题是关于GetAllStudents()方法的实现。它看起来像这样可以吗?
public List GetAllStudents(){
List<StudentDC> studentDCs = new List<StudentDC>(); var students = db.Students_TB.Select(s => s).ToList(); foreach(Student_TB student in students) { StudentDC studentDC = new StudentDC(); studentDC.StudentID = student.StudentID; studentDC.StudentName = student.StudentName; studentDCs.Add(studentDC); } return studentDCs;
}
上述为数据契约赋值的方法是否正确,或者我是否应该让学生业务对象类接受数据访问层中的数据,然后将值传递给服务契约实现中的数据契约,如下所示:
我将有学生业务对象类如下:
公共类StudentBO{
int studentID; string studentName; public int StudentID { get { return studentID; } set { studentID = value; } } public <return type> BusinessLogicMethod1() { // Implementation }
}
在数据访问层中,我将从数据库获得的值分配给学生业务对象集合,如下所示:
public List<StudentBO> GetAllStudents()
{
List<StudentBO> studentBOs = new List<StudentBO>();
var students = db.Students_TB.Select(s => s).ToList();
foreach(Student_TB student in students)
{
StudentBO studentBO = new StudentBO();
studentBO.StudentID = student.StudentID;
studentBO.StudentName = student.StudentName;
studentBOs.Add(studentBO);
}
return studentBOs;
}
学生业务对象中的值随后将被分配给服务契约实现中的学生数据契约,从那里通过网络发送出去。
以上两种方法哪一种是正确的方法?
首先你应该问你的设计目标如下:
- 你的基础层对象改变的频率(例如添加/更新/删除)新字段)? 数据层表更改的频率(重新设计关系、表)结构)?
- WCF域对象更改以满足业务/UI的频率的要求吗?
将数据层与业务对象分离的主要思想是在它们之间有某种程度的抽象。因此,持久层(又名:数据访问层)中的更改不会对更高级的业务逻辑产生重大的连锁反应。业务逻辑也是如此……如果有什么变化……对持久层的更改是最小的。
另一个方面是代码的可测试性。您可以为您的业务逻辑提供单元测试用例,并在没有连接到实际DB的持久层的情况下运行它们。相反,您可以在持久化层中使用"mock"类,这样您就可以在内存中运行所有类,并在不连接到DB的情况下测试业务层。
最后,如果你不希望在你的应用程序的整个生命周期中改变任何一层和维护代码,你可以这样做。但在大多数情况下,应用会发生变化,维护成本是关键因素之一……层间耦合在这里很有帮助。
您还可以考虑使用AutoMapper
如果我理解正确的话,这个问题基本上是以下两个选项中哪个更"正确":
- 数据库数据对象->数据传输对象
- 数据库数据对象->业务对象->数据传输对象
我认为是前者。业务对象的存在是为了封装应用程序业务域的逻辑,dto的存在是为了帮助将数据从应用程序移动到其客户端。不仅从数据库对象复制到业务对象,再从业务对象复制到dto要花费更多的精力,而且有人说(特别是在Command-Query Responsibility Segregation领域)业务对象上的属性甚至不应该公开访问,因为这会暴露它们的内部状态,违反封装。所以,在我看来,直接从ORM数据库对象复制到dto既好又正确。
@user1697575指出AutoMapper帮助你映射是非常正确的:)