1

従業員と部門のデータベースがあるとしましょう。これを処理するための単純なオブジェクトモデルを作成しました:

class Employee
{
   decimal Salary;
   Department Department;
}

class Department
{     
    decimal TotalSalaries; //calculated as the sum of all employees salaries
                           //stored in database, not just a C# property
}

と..

class Employees
{
    void Create(Employee e);
    void Update(Employee e);    
    void Delete(Employee e);
    ...
}

class Departments
{
    ...
}

従業員を更新したい場合は、単に次のようにします。

Employee emp = Employees.GetById(1);
emp.Salary += 100; //salary increase
Employees.Update(emp);

従業員の1人を更新するたびTotalSalariesDepartment自動的に再計算したいのですがSalary

私は次のことができます:

void Update(Employee e)
{
     ... //
     ... // sql stuff to update employee fields.

     Departments.ReCalculateTotalSalaries(e.Department.Id);
}

しかし、そうすると、単一責任の原則に違反すると思います。なぜ従業員の更新方法を気にする必要があるのDepartmentsですか?これは非常に単純な例ですが、エンティティ間に多くの依存関係がある場合、コードが非常に乱雑になる可能性があります。

私はそれを行う他の方法について考えました:

1)従業員のサービスクラスを作成します:EmployeeService。次に、このクラスでUpdate()、従業員を更新するメソッドを定義します。このメソッドは、従業員を更新し、部門の合計を再計算します(もちろん、リポジトリメソッドを呼び出します)。

void Update(Employee e)
{
     Employees.Update(e);
     Departments.ReCalculateTotalSalaries(e.Department.Id);
}

問題:データモデルに多くの依存関係がある場合、モデルレイヤーをほぼ「2倍」にする必要があります(クラスの数x2)。また、コントローラー(またはビュー)がリポジトリを直接呼び出すのではなく、常にサービスメソッドを呼び出すようにするにはどうすればよいですか?


2)Employeesリポジトリには、メソッドOnSalaryChange()から呼び出されるイベントがあります。Update()リポジトリDepartmentsはそれをサブスクライブし、必要に応じて必要な処理を実行します(つまり、call ReCalculateTotalSalaries())。そうすれば、リポジトリにDepartmentsとどまるものは他のエンティティを気にする必要がありません。DepartmentsEmployees

問題:給与が変更されたときに何が起こったのかを(コードを読んだりデバッグモードで)追跡するのが非常に難しくなる可能性があります(複数のサブスクライバーがいる場合)。また、サブスクライバーを特定の順序で呼び出す必要がある場合は、問題になる可能性があります。

4

3 に答える 3

1

データベースに計算フィールドを使用する理由が必要です (パフォーマンス?)。私はそのようなケースをできるだけ避けるようにしています。

原因は更新だけではありません。従業員を削除すると、再計算も必要になります。

しかし、これは危険な場合があります (1 つの理由として、ある日、データベースでスクリプトを使用して作業し、従業員の給与を更新した後で Department テーブルを手動で更新するのを忘れた場合があります)。

そう

  • データベースでトリガーを作成できます(最初にコードがある場合は、いつでもSMOを使用して「コード」ロジックを保持できます)

  • あなたはdbビューを作成することができます

  • DepartmentエンティティにEmployees ICollection(またはIList、または...)を持ち、リストの給与を合計する「単純な取得プロパティ」として総給与を取得できます...

于 2012-04-11T21:40:51.113 に答える
1

あなたの場合、はい、単一責任の原則を破っています。

原則を尊重するために、この行

Departements.ReCalculateTotalSalaries(e.Department.Id);

する必要があります

e.Department.ReCalculateTotalSalaries();

これを行うには、データベースと DB スキーマで 2 つのエンティティ間の関係を使用する必要があります。

編集: ReCalculateTotalSalaries はプロパティを変更する必要がありますが、それ自体をデータベースに保存しないでください。したがって、DB 自体には触れないため、DepartmentRepository ではなく、Departement エンティティに配置する必要があります。

EDIT2:を呼び出すとEmployees.Update(yourEmployee)、yourEmployee.Department も保存されます。それがこのマジックです!Update()エンティティごとに 1 つ呼び出す必要はありません。

于 2012-04-11T21:42:10.257 に答える
-1

他のリポジトリを従業員リポジトリにコンストラクター (または他のタイプ) に注入しないのはなぜですか?

public EmployeeRepository(DepartmentRepository department){}

...次に、必要なものに _department を使用します。それが1つのクリーンな方法です。コード内で複雑なやり取りを行う必要から逃れることはできません。

...または、2つを組み合わせたような「監視」リポジトリを使用し、両方の参照を注入し、最初に従業員のことを行い、次にもう一方を呼び出しますか? 多分それはあなたが考えていることにもっと似ています。
MasterRepository(Employee employee, Department department)... SaveEmployee() { // まず従業員を実行し、次に ... // 部門を呼び出します }

これがいくつかの助けになることを願っています。

編集:私はイベントには行きません-少なくともリポジトリには理由がありますが、最初の理由は、Dbとデータがどこにあるかについて本当に気分が悪いことです。私が理解できなかった最初のオプションは、私のマスターレポに似ているかもしれません。

于 2012-04-11T21:40:03.327 に答える