我试图让 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;
}
}
最佳答案
从技术上讲,您可以引入一个具有显式实现的接口(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/