哪种设计更适合具有大量数据共享的客户机/服务器项目
本文关键字:数据共享 客户机 项目 服务器 | 更新日期: 2023-09-27 18:18:30
假设我们有一个项目,它将处理大量数据(员工、日程安排、日历....)还有更多)。客户端是Windows应用程序,服务器端是WCF。数据库为MS SQL Server。我对使用哪种方法感到困惑。我读了一些文章和博客,他们看起来都很好,但我很困惑。我不想从一种方法开始,然后后悔没有选择另一种方法。该项目将有大约30-35种不同的对象类型。大量的数据检索来填充不同的报告…等
方法1:
// classes that hold data
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
.....
}
public class Assignment
{
public int Id { get; set; }
public int UserId { get; set; }
public DateTime Date { get; set; }
.....
}
.....
然后Helper类处理数据保存和检索:
public static class Employees
{
public static int Save(Employee emp)
{
// save the employee
}
public static Employee Get(int empId)
{
// return the ugly employee
}
.....
}
public static class Assignments
{
public static int Save(Assignment ass)
{
// save the Assignment
}
.....
}
供参考,像Employees和Assignment这样的对象类将在一个单独的程序集中在服务器和客户端之间共享。不管怎样,用这种方法,我将有一个更干净的对象。Helper类将完成大部分工作。
方法2:
// classes that hold data and methods for saving and retrieving
public class Employee
{
// constructors
public Employee()
{
// Construct a new Employee
}
public Employee(int Id)
{
// Construct a new Employee and fills the data from db
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
.....
public int Save()
{
// save the Employee
}
.....
}
public class Assignment
{
// constructors
public Assignment()
{
// Construct a new assignment
}
public Assignment(int Id)
{
// Construct a new assignment and fills the data from db
}
public int Id { get; set; }
public int UserId { get; set; }
public DateTime Date { get; set; }
.....
public int Save()
{
// save the Assignment
}
.....
}
.....
使用这种方法,每个对象将完成自己的工作。数据仍然可以很容易地从WCF传输到客户端,因为WCF只会共享属性。
方法3:
使用实体框架…除了我从未使用过它的事实(这很好,因为我必须学习新的东西),我需要创建poco来在客户端和WCF之间传输数据。
现在,哪个更好?更多的选择吗?
对象本身具有持久逻辑总是一个坏主意。
我会使用第一种方法。它看起来像储存库模式。通过这种方式,您可以轻松地调试数据的持久化,因为它将与对象的其余逻辑清晰地分离。
我建议使用实体框架+存储库模式。这样,你的实体就是没有任何逻辑的简单对象。所有检索-保存逻辑都保留在存储库中。我在使用通用存储库方面有一些成功的经验,它使用实体类型,这里描述了类似的东西(本文的通用存储库部分)。通过这种方式,您只需编写一次存储库代码,并且可以将其重用于所有实体。例如:
interface IRepositry<T>
{
T GetById(long id);
bool Save(T entity);
}
public class Repository<T> : IRepository<T> {...}
var repository = new Repository<MyEntity>();
var myEntity = repository.GetById(1);
var repository2 = new Repository<MySecondEntity>();
var mySecondEntity = repository.GetById(1);
当一个实体需要一些非常具体的操作时,您可以将该操作添加到IRepository的具体类型实现中:
interface IMySuperRepositry : IRepository<MySuperEntity>
{
MySuperEntity GetBySuperProperty(SuperProperty superProperty);
}
public class MySuperEntityRepository : Repository, IMySuperRepository
{...}
要创建存储库,最好使用工厂,例如基于配置文件。这样你就可以切换存储库的实现,例如,对于单元测试,当你不想使用真正访问DB的存储库时:
public class RepositoryFactory
{
IRepository<T> GetRepository<T>()
{
if (config == production)
return new Repository<T>(); // this is implemented with DB access through EF
if (config == test)
return new TestRepository<T>(); // this is implemented with test values without DB access
}
}
}}
您可以为保存添加验证规则,并进一步详细说明这一点。EF还允许您向生成的实体添加一些简单的方法或属性,因为它们都是部分类。
此外,使用poco或STEs(见后面)可以在一个项目中拥有EDMX DB模型,而在另一个项目中拥有所有实体,从而将此DLL分发到客户端(仅包含您的实体)。据我所知,这也是你想要达到的目标。
也要认真考虑使用自我跟踪实体(而不仅仅是poco)。在我看来,它们非常适合与WCF一起使用。当你从DB获得一个实体并将其传递给客户端,客户端更改它并将其返回时,你需要知道,如果实体被更改,以及更改了什么。STEs为您处理所有这些工作,并且是专门为WCF设计的。你从客户端获取实体,说ApplyChanges并保存,就是这样。
如何将Save实现为扩展方法?这样,您的类就像第一个选项一样干净,但方法可以像第二个选项一样在对象上调用。
public static class Employee
{
public static int Save(this Employee emp)
{
// save the employee
}
public static Employee Get(int empId)
{
// return the ugly employee
}
}
你想多了。试图"仅仅因为"或"他们是这么说的"就应用技术和模式,只会使解决方案变得复杂。关键是设计应用程序,使其能够轻松地适应变化。这可能是一个模棱两可的答案,但归根结底就是这样。维护和/或修改代码库需要多少努力。
目前听起来模式和实践是最终结果,而不是达到目的的手段。
实体框架是一个很好的工具,但不一定是在所有情况下的最佳选择。这取决于你希望从数据库中读/写多少,以及你希望从WCF服务中读/写多少。也许有人更精通英孚的精彩世界将能够帮助你。根据我的经验,我曾经在一个以WCF服务端点为特征的应用程序中使用过LINQ-TO-SQL,并且没有出现任何问题(事实上,我开始将LINQ-TO-SQL作为ORM来使用)。
话虽如此,如果你决定EF不是你的正确选择,那么看起来你在方法1的正确轨道上。但是,我建议实现一个数据访问层。也就是说,在您的业务类中实现一个Persist
方法,然后调用单独的DAO(数据访问对象,或用于持久化来自业务对象的数据的类)中的方法,以实际将其保存到数据库中。
示例实现可能如下所示:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public void Persist()
{
EmployeeDAO.Persist(this);
}
}
public class Assignment
{
public int Id { get; set; }
public int UserId { get; set; }
public DateTime Date { get; set; }
public void Persist()
{
AssignmentDAO.Persist(this);
}
}
public static class EmployeeDAO
{
public static int Persist(Employee emp)
{
// insert if new, else update
}
public static Employee Get(int empId)
{
// return the ugly employee
}
.....
}
public static class AssignmentDAO
{
public static int Persist(Assignment ass)
{
// insert if new, else update
}
.....
}
这样的模式的好处是,你可以保持你的业务类干净,你的数据访问逻辑分开,同时仍然给对象提供简单的语法,可以在你的代码中编写new Employee(...).Persist();
。
如果你真的想发疯,你甚至可以考虑在你的持久化类上实现接口,并让你的DAO接受那些IPersistable
实例作为参数。