哪种设计更适合具有大量数据共享的客户端/服务器项目

时间:2011-12-20 18:13:49

标签: c# wcf entity-framework design-patterns

假设我们有一个项目可以处理大量数据(员工,日程安排,日历等等)。客户端是Windows App,服务器端是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; }
    .....
}
.....

然后帮助类处理数据保存和检索:

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这样的对象类将在一个单独的程序集中,以便在Sever和Client之间共享。 无论如何,通过这种方法,我将有一个更清洁的对象。助手课程将完成大部分工作。

方法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:

使用Entity Framework ..除了我从未使用它之外(这很好,因为我必须学习新东西)我需要创建POCO以在客户端和WCF之间传输数据。

现在,哪个更好?更多的选择?

5 个答案:

答案 0 :(得分:2)

在对象中拥有执行逻辑总是一个坏主意。

我会先使用aproach。它看起来像Repository pattern。这样,您就可以轻松地调试数据的持久性,因为它将与对象的其余逻辑明确分开。

答案 1 :(得分:0)

如何实现另存为扩展方法?这样,您的类就像第一个选项一样干净,但是可以像在第二个选项中那样在对象上调用方法。

public static class Employee
{
    public static int Save(this Employee emp)
    {
        // save the employee
    }

    public static Employee Get(int empId)
    {
        // return the ugly employee
    }

}

答案 2 :(得分:0)

你正在考虑这个问题。试图应用技术和模式“仅仅因为”或“他们所说的”只会使解决方案变得复杂。关键是设计应用程序,以便它可以轻松适应变化。这可能是一个模棱两可的答案,但这就是它归结为什么。维护和/或修改代码库需要多少努力。

目前听起来模式和做法是最终结果,而不是达到目的的手段。

答案 3 :(得分:0)

实体框架是一个很好的工具,但不一定是所有情况下的最佳选择。它取决于您希望从数据库读取/写入的数量与您希望读取/写入WCF服务的程度。也许精通EF的精彩世界的人将能够帮助你。从经验来讲,我在一个具有WCF服务端点的应用程序中使用了LINQ-TO-SQL,并且没有任何问题(事实上,它已经将Linq-To-Sql作为ORM来实现)。

话虽如此,如果您认为EF不是您的正确选择,看起来您已经通过方法1 走上正轨。不过,我建议您实施Data Access Layer。也就是说,在业务类中实现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();的简单语法。

如果您真的想要坚持下去,您甚至可以考虑在 Persistable 类上实现接口,并让您的DAO接受那些IPersistable个实例作为参数。

答案 4 :(得分:0)

我建议使用Entity Framework + Repository模式。这样,您的实体就是简单的对象,没有任何逻辑。所有检索 - 保存逻辑都保留在存储库中。我有一些使用通用存储库的成功经验,它使用实体输入,类似的描述here(文章的通用存储库部分)。这样您只需编写一次存储库代码,并且可以将其重用于您拥有的所有实体。例如:

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或STE(见后文),可以在一个项目中使用EDMX DB模型,在另一个项目中使用所有实体,从而将此DLL分发给客户端(仅包含您的实体)。据我所知,这也是你想要实现的目标。

还要认真考虑使用Self tracking entities(而不仅仅是POCO)。在我看来,它们非常适合与WCF一起使用。当您从DB获取实体并将其传递给客户端时,客户端会更改它并将其返回,您需要知道实体是否已更改以及更改了什么。 STE为您处理所有这些工作,专为WCF设计。你从客户那里得到实体,比如说ApplyChanges和Save,就是这样。