【问题标题】:What is the best way to load data to the following structure from database?将数据从数据库加载到以下结构的最佳方法是什么?
【发布时间】:2016-04-23 22:03:10
【问题描述】:

数据库架构如下

员工

  • EmployeeID(int, pk)
  • 名字(nvarchar)
  • 姓(nvarchar)
  • 电子邮件(nvarchar)
  • EmployeeType(int)
  • 工资(十进制)
  • HourlyRate(十进制)

好处

  • BenefitID (int, pk)
  • 好处 (nvarchar)
  • EmployeeID (int, fk)

Employee 表包含所有员工数据。工资字段适用于全职员工,小时费率适用于小时工。福利仅适用于全职员工。

我已经设置了一个服务类,它将返回所有员工。 我还想初始化 Salied Employee 对象的所有好处。我已经使用 switch 语句设置了对员工类型的检查,然后创建对象的实例并将其添加到集合中。

这将完美地工作。

我遇到的问题是每次添加新类型的员工时,我都必须修改 Employee 服务并添加逻辑到 switch 语句来处理新类型的员工。这打破了开闭原则。

我的问题是在这种情况下将数据从数据库加载到对象的最佳方式是什么?

public enum EmployeeType
{
    FullTime =1,
    PartTime =2
}

public class EmployeeBenefit
{
    private string _benefit;
    private Employee _employee;

    public int EmployeeId { get { return Employee.Id; } }
    public Employee Employee { get { return _employee; } }
    public string Benefit { get { return _benefit; } }

    public EmployeeBenefit(Employee emp, string benefit)
    {
        _benefit = benefit;
        _employee = emp;
    }
}

public abstract class Employee
{
    public int Id { get; set; }
    public abstract EmployeeType Type { get; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
}

public class SalariedEmployee: Employee
{
    private ICollection<EmployeeBenefit> _benefits;

    public SalariedEmployee()
    {
        _benefits = new List<EmployeeBenefit>();
    }

    public IEnumerable<EmployeeBenefit> Benefits { get {return _benefits;} }
    public double Salary { get; set; }

    public override EmployeeType Type
    {
        get { return EmployeeType.FullTime; }
    }

    public void AddBenefit(string benefit)
    {
        EmployeeBenefit ebenefit = new EmployeeBenefit(this, benefit);

        if (Benefits.Contains(ebenefit))
            _benefits.Add(ebenefit);
    }

    public void RemoveBenefit(string benefit)
    {
        EmployeeBenefit ebenefit = new EmployeeBenefit(this, benefit);

        if(_benefits.Contains(ebenefit))
            _benefits.Remove(ebenefit);
    }
}

public class PartTimeEmployee : Employee
{
    public override EmployeeType Type
    {
        get { return EmployeeType.PartTime; }
    }

    public double HourlyRate { get; set; }
}

public class EmployeeService
{
    public IEnumerable<Employee> GetAll() {         
        List<Employee> _lst = new List<Employee>();

        using(var db = new EmployeeContext)
        {

            foreach(Employee e in db.Employees)
            {

                switch(e.Type){
                    case EmployeeType.PartTime:
                        PartTimeEmployee pt = new PartTimeEmployee();
                        //initialize the values of parttime employee like hourly rate

                        _lst.Add(pt);
                        break;
                    case EmployeeType.FullTime:
                        SalariedEmployee se = new SalariedEmployee();
                        //initialize the value of salaried employees like benefits, salary
                        _lst.Add(se);
                        break;
                }

            }


        }

        return _lst;
    }
}

【问题讨论】:

  • 你可以在工厂类中移动这个逻辑......类将有工作来检查类型并创建适当类型的实例......基本上你正在移动那个类中的 switch 语句并且只需要修改那个每次上课
  • 我考虑过使用工厂方法,该方法将返回一个适当的 Employee 实例,但我如何设置所有相关属性,如福利、小时费率和薪水,因为它们基于子对象。我在这里很困惑。
  • 添加IPartTimeEmployee、ISalariedEmployee等接口怎么样
  • 我可以将薪水和福利移动到 ISalariedEmployee 并将 HourlyRate 移动到 IPartTimeEmployee,但问题仍然是如何将数据加载到各自的属性中。我可以检查从工厂类返回的对象是否是 ISalariedEmployee 或 IPartTimeEmployee 类型并设置值,但我再次引入了检查服务类中返回的对象类型的逻辑。我的想法是对的吗?

标签: c# design-patterns


【解决方案1】:

您可以做的只是将员工类型保留为 Employee 类中的 String 属性,然后将类型动态添加到 Employee 类中。我在这里看不到 Employee Type 类的实际需要。

如果您绝对需要这样的类,请将其声明为类而不是枚举,并具有将作为类型名称的字符串属性。之后,对于从查询中获得的每个新类型,初始化一个 new EmployeeType() 并使用 setter 添加该字符串。然后将该 EmployeeType 设置为 Employee 类。

在我看来,这是一个更好的设计,因为您不需要对枚举中的字符串值进行硬编码。

对于好处,您可以做的是为具体的 Employee 类添加一个好处属性(或者将其命名为其他名称,因为您已经有了一个抽象的 Employee)。并且仅当员工类型为受薪时才为福利设置一个值。我就是这样做的。

【讨论】:

  • 感谢您的回复。但我有一个问题。由于福利仅适用于受薪员工,因此我必须查询数据库以加载员工的福利并调用 AddBenefit 函数;至于小时工,我不需要做任何事情,因为福利不适用。因此,如果我的服务类有一个返回所有员工的函数,我如何设置数据库中的所有值。 Employee 是一个抽象类,所以我需要传递 Salried 或 Hourly 的实例,
  • 我拥有的代码使用 switch 语句来检查实例是否有效,但我正在寻找一种更好的方法来加载数据,因为如果我必须添加更多类型的员工,那么我必须来返回并修改switch语句来处理它。这有意义吗?
  • 您可以做的是为具体的 Employee 类添加一个好处属性(或者将其命名为其他名称,因为您已经有一个抽象的 Employee)。并且仅当员工类型为受薪时才为福利设置一个值。我就是这样做的。
  • 谢谢普里塔姆,但这是一种解决方法。至于 HourlyEmployee 没有任何好处,因此从 OOP 的角度来看,将好处转移到抽象类是没有意义的。如果我将好处转移到抽象类,那么从 Employee 类继承的任何类都可以访问此属性。 :-(
  • 我明白你在说什么。那么唯一的方法就是为每种类型创建单独的具体类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
  • 2012-01-05
  • 1970-01-01
  • 1970-01-01
  • 2018-10-16
相关资源
最近更新 更多