实体框架IValidatableObject参考DbContext [英] Entity Framework IValidatableObject reference DbContext

查看:72
本文介绍了实体框架IValidatableObject参考DbContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使EF 4.1与存储库,UnitOfWork,将实体与EF分离以及进行验证有关.

I'm trying to get EF 4.1 working with Repository, UnitOfWork, separation of entities from EF and validation.

我遵循了指南可以很好地将我的POCO实体与EF模型区分开来,我现在正在按照

I followed this guide to get a nice separation of my POCO entities from the EF model and I'm now following this guide to implement validation (with IValidatableObject).

我的解决方案包括:

  • Contacts.Repository [引用EF和Contacts.Entities]:
    • Contacts.edmx
    • ContactsDbContext.cs
    • Contacts.Repository [references EF and Contacts.Entities]:
      • Contacts.edmx
      • ContactsDbContext.cs
      • Contact.cs(Contacts.Entities.Contact局部类)
      • Contact.cs(Contacts.Entities.Contact局部类)

      但是我正在通过验证碰到一堵砖墙:

      But I'm hitting a brick wall with the validation:

      1. 我无法向Contacts.Entities添加验证逻辑,因为这会导致对Contacts.Repository进行循环引用(contact.Validate(...)需要使用ContactsDbContext).因此,我创建了一个单独的Contacts.Validation项目.
      2. 但是,这意味着将Contact类分为部分类,以在Contacts.Entities和Contacts.Validation中定义Contact.该代码不再编译,因为您无法跨不同的程序集定义局部类.

      有人在这里给我指点吗?我已经在下面发布了代码...

      Anyone got any pointers for me here? I've posted the code below...

      Contacts.Repository.ContactsDbContext.cs:

      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:

      Contacts.Entities.Contact.cs:

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

      Contacts.Validation.Contact.cs包含:

      Contacts.Validation.Contact.cs contains:

      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;
            }
        }
      

      推荐答案

      技术上,您可以引入具有如下所示的显式实现的接口:

      Technically you could introduce an interface with an explicit implementation like so:

      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 程序集):

      In Contacts.Repository assembly (references Contacts.Entities assembly):

      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 程序集.

      但是,我不太喜欢这种解决方案.通过Validate方法,您的POCO仍然依赖于存储库(无论是否存在接口).为了更好地分离关注点,我可能希望拥有一个单独的Validation类,该类也可能对存储库进行操作.或者,如果我要实现IValidatableObject,我可能只会进行仅依赖于模型对象属性的验证(例如生产日期一定不能晚于发货日期"之类的东西).好吧,这只是部分品味问题.您链接的第二个示例并不真正关心关注点的分离,因此您与第一个示例存在某种冲突.

      However, I do not really like this solution. Your POCO has - through the Validate method - still a dependency on the repository, if interface or not. For a stronger separation of concerns I would probably prefer to have a separate Validation class which does perhaps also operations on the repo. Or if I would implement IValidatableObject I would probably only do validations which depend on model object properties alone (things like "production date must not be later than shipping date" and so on). Well, it's partially a matter of taste. The second example you have linked does not really care about separation of concerns, so you have somehow a conflict with the first example.

      这篇关于实体框架IValidatableObject参考DbContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆