9

私はEntityFrameworkを使用しており、DDDの原則を使用したいと考えています。ただし、ロギング/永続性情報とドメインオブジェクトに関する情報の境界にあるエンティティに関する情報がいくつかあります。

私の状況では、これらはすべてのエンティティが継承する抽象基本クラスに配置されます。

 public abstract class BaseEntity: IBaseEntity
{

    /// <summary>
    /// The unique identifier
    /// </summary>
    public int Id { get; set; }

    /// <summary>
    /// The user that created this instance
    /// </summary>
    public User CreatedBy { get; set; }

    /// <summary>
    /// The date and time the object was created
    /// </summary>
    public DateTime CreatedDate { get; set; }

    /// <summary>
    /// Which user was the last one to change this object
    /// </summary>
    public User LastChangedBy { get; set; }

    /// <summary>
    /// When was the object last changed
    /// </summary>
    public DateTime LastChangedDate { get; set; }

    /// <summary>
    /// This is the status of the entity. See EntityStatus documentation for more information.
    /// </summary>
    public EntityStatus EntityStatus { get; set; }

    /// <summary>
    /// Sets the default value for a new object
    /// </summary>
    protected BaseEntity()
    {
        CreatedDate = DateTime.Now;
        EntityStatus = EntityStatus.Active;
        LastChangedDate = DateTime.Now;
    }

}

現在、ドメインオブジェクトは、日付と時刻を指定せずにインスタンス化することはできません。しかし、それを置くのは間違った場所だと思います。私は本当に両方について議論することができます。多分それはドメインと全く混合されるべきではありませんか?

私はEFCodeFirstを使用しているので、そこに配置するのが理にかなっています。そうしないと、DALの基本クラスから継承する新しいクラスを作成し、コードを複製して、ドメインオブジェクトとMVCモデルの両方にマップする必要があります。上記のアプローチよりも厄介に見えます。

質問):

ドメインモデルでDateTime.Nowを使用しても大丈夫ですか?DDDとEFコードファーストを使用して、この種の情報をどこに配置しますか?ユーザーをドメインオブジェクトに設定する必要がありますか、それともビジネスレイヤーで要求する必要がありますか?

アップデート

jgauffinはここで正しい答えだと思いますが、それは本当に根本的な変化です。しかし、別の解決策を探していたところ、ほとんどこれで解決できました。ChangeTracker.Entriesを使用して、エンティティが追加または変更されているかどうかを確認し、それに応じてフィールドを設定しました。これは私のUnitOfWorkSave()メソッドで行われます。

問題は、Userなどのナビゲーションプロパティの読み込みです(DateTimeが正しく設定されています)。これは、ユーザーがエンティティの継承元の抽象基本クラスのプロパティであるためである可能性があります。私もそこに文字列を入れるのは好きではありませんが、誰かのためにいくつかの簡単なシナリオを解決するかもしれないので、ここに解決策を投稿します:

        public void SaveChanges(User changedBy)
    {
        foreach (var entry in _context.ChangeTracker.Entries<BaseEntity>())
        {
            if (entry.State == EntityState.Added)
            {
                entry.Entity.CreatedDate = DateTime.Now;
                entry.Entity.LastChangedDate = DateTime.Now;
                entry.Entity.CreatedBy = changedBy;
                entry.Entity.LastChangedBy = changedBy;
            }
            if (entry.State == EntityState.Modified)
            {
                entry.Entity.CreatedDate = entry.OriginalValues.GetValue<DateTime("CreatedDate");
                entry.Entity.CreatedBy = entry.OriginalValues.GetValue<User>("CreatedBy");
                entry.Entity.LastChangedDate = DateTime.Now;
                entry.Entity.LastChangedBy = changedBy;
            }
        }


        _context.SaveChanges();
    }
4

2 に答える 2

3

Domain モデルで DateTime.Now を使用してもよろしいですか?

はい。

DDD と EF Code First を使用して、この種の情報をどこに置きますか? ユーザーをドメイン オブジェクトに設定する必要がありますか、それともビジネス レイヤーでそれを要求する必要がありますか?

良い。まず第一に、DDD モデルは常に有効な状態にあります。これはパブリック セッターでは不可能です。DDD では、必要なすべての情報が指定され、有効であることをメソッドによって確認できるため、メソッドを使用してモデルを操作します。

たとえば、アイテムを完了としてマークできる場合、UpdatedAt日付も変更する必要がある可能性があります。呼び出しコードにそれを確認させると、どこかで忘れられる可能性があります。代わりに、次のようなものが必要です。

public class MyDomainModel
{
    public void MarkAsCompleted(User completedBy)
    {
        if (completedBy == null) throw new ArgumentNullException("completedBy");
        State = MyState.Completed;
        UpdatedAt = DateTime.Now;
        CompletedAt = DateTime.Now;
        CompletedBy = completedBy;
    }
}

そのアプローチに関する私のブログ記事を読んでください: http://blog.gauffin.org/2012/06/protect-your-data/

アップデート

後で誰も「CreatedBy」と「CreatedDate」を変更しないようにする方法

私は通常、DBにも適合するモデル用の2つのコンストラクターを持っています。1 つは永続化レイヤーで使用できる保護されたもので、もう 1 つは必須フィールドを必要とするものです。そのコンストラクターにcreatedbyを入れ、createdateを設定します。

public class YourModel
{
    public YourModel(User createdBy)
    {
        CreatedDate = DateTime.Now;
        CreatedBy = createdby;
    }

    // for persistance
    protected YourModel()
    {}
}

次に、それらのフィールドのプライベート セッターを用意します。

「コンストラクターでの仮想メンバー呼び出し」という R# の警告がたくさん表示されます。以前にそれについて読んだことがありますが、それは良い習慣ではありません。

それは通常問題ではありません。ここを読む:コンストラクターでの仮想メンバー呼び出し

于 2012-10-18T08:55:46.183 に答える
2

Domain モデルで DateTime.Now を使用してもよろしいですか?

ひどいことではありませんが、問題は、コードを複製しなければならなくなり、一貫性を保つことがより困難になることです。

DDD と EF Code First を使用して、この種の情報をどこに置きますか?

この種の情報はあなたのドメインに属していないと主張するのは正しいです。これは通常、監査ログまたは証跡と呼ばれます。EF を使用して監査を実装するには、いくつかの方法があります。たとえば、AuditDbContext - Entity Framework Auditing Contextを参照するか、単に EF 監査の実装を検索してください。これは、EF がエンティティへの変更を保持する前に、必要な監査値をリッスンして割り当てることができるイベントを発生させるというものです。

ユーザーをドメイン オブジェクトに設定する必要がありますか、それともビジネス レイヤーでそれを要求する必要がありますか?

上記のように、監査の実装を使用してインフラストラクチャ/リポジトリ レベルでこれを処理することをお勧めします。これは、データが永続化される前の最終停止であるため、これを処理するのに最適な場所です。

于 2012-10-17T19:24:15.277 に答える