2011-06-27 38 views
6

Tôi đang cố gắng để có được EF 4.1 làm việc với Repository, UnitOfWork, tách các thực thể khỏi EF và xác thực.Entity Framework IValidatableObject tham chiếu DbContext

Tôi theo dõi this hướng dẫn để có được sự tách biệt tốt đẹp của các thực thể POCO của tôi từ mô hình EF và giờ tôi đang theo dõi hướng dẫn this để triển khai xác thực (với IValidatableObject).

giải pháp của tôi bao gồm:

  • Contacts.Repository [tài liệu tham khảo EF và Contacts.Entities]:
    • Contacts.edmx
    • ContactsDbContext.cs
  • Contacts.Entities [không có tham chiếu]:
    • Contact.cs (Contacts.Entities.Contact phần lớp)
  • Contacts.Validation [tài liệu tham khảo Contacts.Entities và Contacts.Repository]
    • Contact.cs (Contacts.Entities.Contact partial class)

Nhưng tôi đánh một bức tường gạch với xác nhận:

  1. Tôi không thể thêm logic xác nhận vào Contacts.Entities vì ​​nó sẽ gây ra tham chiếu vòng tròn với Contacts.Repository (contact.Validate (...) cần sử dụng ContactsDbContext). Vì vậy, tôi đã tạo một dự án Contacts.Validation riêng biệt.
  2. Tuy nhiên, điều này có nghĩa là tách lớp Liên hệ với các lớp một phần để xác định Liên hệ trong cả Contacts.Entities và Contacts.Validation. Mã không còn biên dịch vì bạn không thể định nghĩa một lớp một phần trên các assembly khác nhau.

Bất kỳ ai cũng có bất kỳ gợi ý nào cho tôi ở đây? Tôi đã đăng mã dưới đây ...

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 chứa:

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

Trả lời

7

Về mặt kỹ thuật bạn có thể giới thiệu một giao diện với một thực hiện rõ ràng như vậy:

Trong Contacts.Entities lắp ráp:

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 
} 

Trong Contacts.Repository lắp ráp (tài liệu tham khảo Danh bạ.Đối tượng lắp ráp):

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 lắp ráp có thể được gỡ bỏ.

Tuy nhiên, tôi không thực sự thích giải pháp này. POCO của bạn có - thông qua phương thức Validate - vẫn còn phụ thuộc vào kho lưu trữ, nếu giao diện hay không. Để phân tách mối quan tâm mạnh mẽ hơn, tôi có thể muốn có một lớp Validation riêng biệt mà có lẽ cũng hoạt động trên repo. Hoặc nếu tôi sẽ thực hiện IValidatableObject Tôi có lẽ sẽ chỉ làm xác nhận mà phụ thuộc vào mô hình đối tượng tài sản một mình (những thứ như "ngày sản xuất không được muộn hơn ngày vận chuyển" và như vậy). Vâng, đó là một phần một vấn đề của hương vị. Ví dụ thứ hai bạn đã liên kết không thực sự quan tâm đến việc phân tách các mối quan tâm, vì vậy bạn đã bằng cách nào đó xung đột với ví dụ đầu tiên.

+0

Cảm ơn. - đó là một bước gần hơn. Tôi đồng ý, tôi muốn chia tách nhiều mối quan tâm hơn. Làm thế nào bạn thường tách ra Xác nhận từ Kho lưu trữ (bất kể EF)? Tôi có một mẫu xác nhận và Repository tốt cho phép tách hoàn toàn ... nhưng sau đó bạn có vấn đề mà người gọi có thể không gọi Validate trước khi gọi Save on the Repository. NB - bây giờ tôi đang phải đối mặt với tham chiếu khung thực thể trong người gọi vì xác nhận sẽ nâng cao một loại System.Data.Entity.Validation.DbEntityValidationException. Tôi thấy đây là một cuộc chiến khó chịu chống lại EF !!! – Matt

+1

@Matt: Tôi không có sự tách biệt rõ ràng giữa xác thực và repo. Việc xác thực rằng một trường cụ thể phải là duy nhất là từ quan điểm của tôi không phải là xác nhận hợp lệ trên cấp thực thể. Nó cũng có thể được coi như là một xác nhận của repo (repo sẽ trở thành không hợp lệ * nếu * tôi muốn chèn một thực thể có cùng tên). Thông thường tôi truy cập repos của tôi thông qua các lớp học dịch vụ và ở đó tôi làm một "kiểm tra" trước khi tôi chèn nếu đã có một thực thể có cùng tên. Không phải xác thực được tách biệt rõ ràng. Nó có thể trở nên dễ dàng hơn và sạch hơn khi EF cung cấp tính năng "Unique Constraints" được đề cập trong bài đăng blog thứ hai. – Slauma

+0

Tôi đang sử dụng DataAnnotation để cung cấp xác thực cấp thực thể. Tôi đồng ý kiểm tra tính duy nhất là một mức độ xác nhận khác và nó không thực sự là trên thực thể. TBH, tôi cảm thấy như EF đang ép tôi xuống con đường này. Tôi sẽ xem xét di chuyển nó vào kho lưu trữ. Cảm ơn bạn đã giúp đỡ. – Matt

1

Xác thực rằng một trường cụ thể phải là duy nhất là từ quan điểm của tôi không phải là xác thực trên đối tượng mức. Nó cũng có thể được coi là xác nhận của repo (repo sẽ trở thành không hợp lệ nếu tôi chèn một thực thể có cùng tên).

Thông thường tôi truy cập repos của tôi thông qua các lớp dịch vụ và ở đó tôi thực hiện "kiểm tra" trước khi tôi chèn nếu đã có một thực thể có cùng tên. Không phải xác thực được tách biệt rõ ràng. Nó có thể trở nên dễ dàng hơn và sạch hơn khi EF cung cấp tính năng "Unique Constraints" được đề cập trong bài đăng blog thứ hai.

~ Slauma Jun 28 '11 at 17:14

nhận xét này xứng đáng là một câu trả lời

Các vấn đề liên quan