web-dev-qa-db-ja.com

コードファーストアプローチとビジネスクラスの検証

ソリューションを2つのプロジェクトに分割しています:すべてのモデルクラスを含むクラスライブラリ(Businessと呼びましょう)とASP.NetMVCプロジェクト。

私のBusinessクラスは、一般的であり、複数のタイプのプロジェクトで機能することを目的としています。このため、データ注釈/アソシエーションは含まれていません他のクラスに対しては、メンバー変数/プロパティ/コンストラクター

コードファーストアプローチを使用して、Businessモデルで動作するようにASP.Netモデルをどのように設計する必要がありますか。

私が最初に教えたのは、Businessクラスを部分クラスとして設定し、必要なデータアノテーションを追加してプロパティを上書きすることでした/アソシエーション。私たちは2つの別々のプロジェクトを扱っているので、それはできません。

また、継承を使用できると考えていました。 ASP.Netモデルはビジネスクラスから継承でき、データ注釈/アソシエーションその上に。ただし、この新しいサブクラスですべてのコンストラクターを定義する必要があるため、これは少し厄介で非論理的なようです。

これをきれいに行う賢い方法はありますか?

編集:

私のBusinessクラスには、プロパティセッターで例外をスローすることによる検証があります。私の最初の設計は、セッターによってスローされた例外をキャッチする独自のカスタムデータ注釈を作成することでした:

public class SetterBasedValidation : ValidationAttribute
    {
        string m_errorMessage = null;
        public SetterBasedValidation(string errorMessage)
        {
            m_errorMessage = errorMessage;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            try
            {
                Type type = validationContext.ObjectType;
                PropertyInfo property = type.GetProperty(validationContext.MemberName);
                property.SetValue(validationContext.ObjectInstance, value);
            }
            catch (Exception)
            {
                return new ValidationResult(m_errorMessage);
            }

            return ValidationResult.Success;
        }
    }

次に、ASP.Netモデルクラスでカスタムデータ注釈を使用する方法が必要になります。これは私が望む結果を私に与えるでしょう:

  • 私のビジネスクラスを一般的に保つ
  • 私のセッターからの検証を使用してください
  • データ注釈を使用する

編集2:

これが私のソリューション設定がどのように見えるかの基本的な概要です。私のビジネスクラス(ドメインモデル)には、次のようなコードが含まれています。

 public class User
    {

        private string m_name = null;

        public string Name
        {
            get { return m_name; }
            set
            {
                string name = value.Trim();

                if (name.Length > 20 || name.Length < 1)
                {
                    throw new ArgumentException("Name length invalid.");
                }
                m_name = name;
            }
        }
    }

enter image description here

1
Corb3nik

Webサイトには、ドメインモデルとページに必要なその他のデータ/ロジックをラップするViewModelの個別のセットが必要です。

これらのビューモデルはドメインではなくWebサイトに属しているため、実装している特定のプロセスについてWebサイト/ビューでのみ必要とされる検証または追加のロジックに固執してもかまいません。

最良の例は、ドメインモデルにサインアップする人に関する大量のデータが含まれるプロセス「サインアップ」があると言うことだと思います。あなたのデザインチームは2つのデザインを考え出します。

  • デザイン1:すべてのフィールドがオンになっている大きな単一ページフォーム

  • デザイン2:複数の個別のフォームを使用した「ウィザード」アプローチ

どちらのデザインも、サインアップに同じ基本ロジックを使用していますが。それぞれが非常に異なるビューモデルを持ちます。

更新---

Entity Frameworkのデータ注釈により、EFはオブジェクトをデータベーステーブルに正しくマップできます。プロパティの一部を使用しないことで回避できるいくつかの規則があり、期待どおりに名前が付けられています。

ただし、ドメインオブジェクトを永続化ロジックから分離する場合は、ドメインオブジェクトのプロパティをミラーリングし、データアノテーションを追加できるエンティティオブジェクトを実装する必要があるという点で正しいです。

これらすべてをリポジトリオブジェクトにラップして、エンティティオブジェクトをDBから取得し、ドメインオブジェクトに変換して、呼び出し元のコードに返すことができます。ただし、これらすべてのことを行うと、EFの時間節約のメリットが失われ、SqlClientを使用しただけの場合もあります。

理想的な世界では、ソリューションの構造は次のようになります。

DomainModels - class lib
    User.cs

EntityModels - class lib
    UserEntity.cs - with data annotations

RepositoryEF - class lib ref domain and entity
    UserRepository.cs - eg. public User GetUser(string id)

Website - ref the other three
    UserController.cs - calls repository to get a domain object
    UserViewModel.cs - populated from domain object by controller
    UserView.cshtml - uses viewmodel as its model and displays data to user
2
Ewan