我试图让EF 4.1与Repository,UnitOfWork合作,将实体与EF分离并进行验证。
我按照this指南将我的POCO实体与EF模型分开,我现在按照this指南实现验证(使用IValidatableObject)。
我的解决方案包括:
但是我在验证时遇到了一堵砖墙:
有人在这里有任何指示吗?我已经发布了以下代码......
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;
}
}
答案 0 :(得分:7)
技术上你可以引入一个具有明确实现的接口,如下所示:
在 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类,它也可能对repo进行操作。或者,如果我实现IValidatableObject
,我可能只会进行仅依赖于模型对象属性的验证(例如“生产日期不得晚于发货日期”等等)。嗯,这部分是品味问题。您链接的第二个示例并不关心问题的分离,因此您与第一个示例存在某种冲突。
答案 1 :(得分:1)
特定字段必须唯一的验证来自我的观点,而不是实体级别的验证。它也可以被视为对repo的验证(如果我插入一个具有相同名称的实体,则repo将变为无效)。
通常我通过服务类访问我的repos,如果已经存在一个具有相同名称的实体,我会在插入之前进行“检查”。不是一个干净利落的验证。当EF提供第二篇博文中提到的“唯一约束”功能时,它可能会变得更容易和更清晰。
此评论值得回答