validation - Entity Framework IValidatableObject 引用 DbContext

标签 validation entity-framework-4.1 dbcontext

我试图让 EF 4.1 与 Repository、UnitOfWork、EF 实体分离和验证一起工作。

我关注了this将我的 POCO 实体与 EF 模型很好分离的指南,我现在正在关注 this实现验证的指南(使用 IValidatableObject)。

我的解决方案包括:

  • Contacts.Repository [引用 EF 和 Contacts.Entities]:
  • Contacts.edmx
  • 联系人DbContext.cs
  • Contacts.Entities [无引用]:
  • Contact.cs(Contacts.Entities.Contact 部分类)
  • Contacts.Validation [引用 Contacts.Entities 和 Contacts.Repository]
  • Contact.cs(Contacts.Entities.Contact 部分类)

  • 但是我在验证中遇到了障碍:
  • 我无法向 Contacts.Entities 添加验证逻辑,因为它会导致使用 Contacts.Repository 进行循环引用(contact.Validate(...) 需要使用 ContactsDbContext)。所以我创建了一个单独的 Contacts.Validation 项目。
  • 但是,这意味着将 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;
          }
      }
    

    最佳答案

    从技术上讲,您可以引入一个具有显式实现的接口(interface),如下所示:

    联系人.实体 部件:

    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方法 - 仍然依赖于存储库,如果接口(interface)与否。为了更好地分离关注点,我可能更喜欢有一个单独的 Validation 类,它可能也对 repo 进行操作。或者,如果我实现 IValidatableObject我可能只会进行仅依赖于模型对象属性的验证(例如“生产日期不得晚于发货日期”等)。嗯,这部分是口味问题。您链接的第二个示例并不真正关心关注点分离,因此您与第一个示例存在某种冲突。

    关于validation - Entity Framework IValidatableObject 引用 DbContext,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6495157/

    相关文章:

    entity-framework-4.1 - 实体和存储库模式与 ninject、Dispose Issue

    java - 开始日期和完成日期验证 - Entity Hibernate java

    jQuery 插件验证 : onfocusin doesn't works

    javascript - onkeypress 可以工作,但 onblur 不能

    python - 是否可以在 ValidationError 的字符串中使用模板标签?

    entity-framework - Entity Framework 4.1 检索自引用数据

    c# - 从 NHibernate 迁移到 Entity Framework 4.1?

    .net - 创建我们自己的 UoW/Repository 与直接使用 DbContext 之间的区别

    c# - MVC 中每个请求的带有 Owin DbContext 的 Entity Framework

    entity-framework - 如何在 ServiceStack Core 中注册 DbContext EF Core?