8

EF 4.1 をリポジトリ、UnitOfWork、EF からのエンティティの分離、および検証と連携させようとしています。

このガイドに従って、POCO エンティティを EF モデルから適切に分離しました。現在、このガイドに従って検証を実装しています (IValidatableObject を使用)。

私のソリューションは次のもので構成されています。

  • Contacts.Repository [EF と Contacts.Entities を参照]:
    • 連絡先.edmx
    • ContactsDbContext.cs
  • Contacts.Entities [参照なし]:
    • Contact.cs (Contacts.Entities.Contact 部分クラス)
  • Contacts.Validation [Contacts.Entities と Contacts.Repository を参照]
    • Contact.cs (Contacts.Entities.Contact 部分クラス)

しかし、私は検証でレンガの壁にぶつかっています:

  1. Contacts.Repository との循環参照が発生するため、Contacts.Entities に検証ロジックを追加できません (contact.Validate(...) は ContactsDbContext を使用する必要があります)。そこで、別の Contacts.Validation プロジェクトを作成しました。
  2. ただし、これは Contact クラスを部分クラスに分割して、Contacts.Entities と Contacts.Validation の両方で Contact を定義することを意味します。異なるアセンブリ間で部分クラスを定義できないため、コードはコンパイルされなくなります。

ここで誰かが私に何かポインタを持っていますか? 私は以下のコードを投稿しました...

Contacts.Repository.ContactsDbContext.cs:

namespace Contacts.Repository
{
  public partial class ContactsDbContext : DbContext
  {
    public DbSet<Contact> Contacts { get; set; }

    protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
    {
      items.Add("Context", this);
      return base.ValidateEntity(entityEntry, items);
    }
  }
}

Contacts.Entities.Contact.cs:

namespace Contacts.Entities
{
    public partial class Contact
    {
        public string Name { get; set; }
    }
}

Contacts.Validation.Contact.cs には以下が含まれます。

namespace Contacts.Entities
{
  public partial class Contact : IValidatableObject
  {
      public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
      {
          ContactsDbContext contacts = (ContactsDbContext)validationContext.Items["Context"];

          //Check if Contact already exists with the same Name
          if (contacts.Any<Contact>(c => c.Name == this.Name))
            yield return new ValidationResult("Contact 'Name' is already in use.", new string[] { "Name" });

          yield break;
      }
  }
4

2 に答える 2

10

技術的には、次のように明示的な実装を使用してインターフェイスを導入できます。

Contacts.Entitiesアセンブリ内:

public interface IContactsDbContext
{
    IQueryable<Contact> Contacts { get; }
    // Not DbSet<Contact> because you don't want dependency on EF assembly 
}

//...

public class Contact : IValidatableObject // No partial class anymore
{
    public string Name { get; set; }

    public IEnumerable<ValidationResult> Validate(
        ValidationContext validationContext)
    {
        IContactsDbContext context = 
            validationContext.Items["Context"] as IContactsDbContext;

        if (context.Contacts.Any<Contact>(c => c.Name == this.Name))
            yield return new ValidationResult(
                "Contact 'Name' is already in use.", new string[] { "Name" });

        yield break;
    }
    // IValidatableObject, ValidationResult and ValidationContext is in
    // System.ComponentModel.DataAnnotations.dll, so no dependency on EF
}

Contacts.Repositoryアセンブリ内 ( Contacts.Entitiesアセンブリを参照):

public class ContactsDbContext : DbContext, IContactsDbContext
{
    public DbSet<Contact> Contacts { get; set; }

    IQueryable<Contact> IContactsDbContext.Contacts // explicit impl.
    {
        get { return Contacts; } // works because DbSet is an IQueryable
    }

    protected override DbEntityValidationResult ValidateEntity(
        DbEntityEntry entityEntry, IDictionary<object, object> items)
    {
        items.Add("Context", this);
        return base.ValidateEntity(entityEntry, items);
    }
}

Contacts.Validationアセンブリは削除できます。

しかし、私はこの解決策があまり好きではありません。あなたの POCO はValidate、インターフェースかどうかに関係なく、メソッドを通じて、まだリポジトリに依存しています。懸念をより強力に分離するために、おそらくレポでの操作も行う別の Validation クラスを用意することをお勧めします。または、実装する場合はIValidatableObject、モデル オブジェクトのプロパティのみに依存する検証のみを行うことになります (「製造日が出荷日より遅くなってはならない」など)。まあ、それは部分的に好みの問題です。あなたがリンクした2番目の例は、関心の分離をあまり気にしていないため、最初の例とは何らかの矛盾があります。

于 2011-06-27T18:25:05.260 に答える
1

特定のフィールドが一意でなければならないという検証は、エンティティレベルでの検証ではなく、私の観点からです。これは、レポの検証と見なすこともできます(同じ名前のエンティティを挿入すると、レポは無効になります)。

通常、サービス クラスを介してリポジトリにアクセスし、同じ名前のエンティティが既に存在するかどうかを挿入する前に「チェック」を行います。明確に分離された検証ではありません。EF が 2 番目のブログ投稿で言及されている "Unique Constraints" 機能を提供すると、より簡単でクリーンになる可能性があります。

〜Slauma 28 6月. 112011-06-28 17:14:00

このコメントは答えに値する

于 2016-06-06T09:42:59.680 に答える