Tôi đang sử dụng không gian tên System.ComponentModel.DataAnnotations
để xác thực các lớp miền của mình. Làm cách nào tôi có thể tạo thuộc tính tùy chỉnh để xác thực tính duy nhất của thuộc tính bất kể cơ sở dữ liệu (thông qua một số giao diện) chẳng hạn?Ràng buộc duy nhất với chú thích dữ liệu
Trả lời
Nếu tôi hiểu bạn đúng cách, bạn sẽ có thể tạo một ValidationAttribute tùy chỉnh và nhận bối cảnh cho kho lưu trữ của bạn thông qua một nhà máy tùy chỉnh.
Validator:
using System.ComponentModel.DataAnnotations;
public class DBUniqueAttribute : ValidationAttribute
{
private IRepository Repository{ get; set;}
public DBUniqueAttribute()
{
this.Repository = MyRepositoryFactory.Create();
}
public override bool IsValid(object value)
{
string stringValue = Convert.ToString(value, CultureInfo.CurrentCulture);
return Repository.IsUnique(stringValue);
}
}
Bạn sẽ có một giao diện IRepository với một phương pháp IsUnique(). MyRepositoryFactory sẽ có một phương thức tĩnh gọi là Create() để tạo ra Kho lưu trữ cụ thể cần thiết cho cơ sở dữ liệu của bạn. Nếu kiểu cơ sở dữ liệu thay đổi, bạn chỉ cần cập nhật Nhà máy để trả về một Kho lưu trữ mới cho cơ sở dữ liệu mới của bạn.
Đây là giải pháp tôi đã đưa ra cho tình huống này, nó chỉ cần kiểm tra bảng cho một bản ghi với một id khác có cùng giá trị cho thuộc tính được xác thực. Nó giả định rằng bạn sẽ sử dụng LinqToSQL và rằng bất kỳ bảng nào mà loại xác thực này được yêu cầu có một cột ID duy nhất.
Tôi cũng sẽ đặt một ràng buộc duy nhất trên bảng cơ sở trong cơ sở dữ liệu. Thuộc tính này cho phép tôi đặt một thông báo lỗi đẹp trên biểu mẫu và liên kết nó với thuộc tính thích hợp.
public class UniqueAttribute : ValidationAttribute
{
public Func<DataContext> GetDataContext { get; private set; }
public string IDProperty { get; private set; }
public string Message { get; private set; }
public UniqueAttribute(Type dataContextType, string idProperty, string message)
{
IDProperty = idProperty;
Message = message;
GetDataContext =() => (DataContext)Activator.CreateInstance(dataContextType);
}
public UniqueAttribute(Type dataContextType, string idProperty, string message, string connectionString)
{
IDProperty = idProperty;
Message = message;
GetDataContext =() => (DataContext)Activator.CreateInstance(dataContextType, new object[] { connectionString });
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var idProperty = validationContext.ObjectType.GetProperty(IDProperty);
var idType = idProperty.PropertyType;
var id = idProperty.GetValue(validationContext.ObjectInstance, null);
// Unsightly hack due to validationContext.MemberName being null :(
var memberName = validationContext.ObjectType.GetProperties()
.Where(p => p.GetCustomAttributes(false).OfType<DisplayAttribute>().Any(a => a.Name == validationContext.DisplayName))
.Select(p => p.Name)
.FirstOrDefault();
if (string.IsNullOrEmpty(memberName))
{
memberName = validationContext.DisplayName;
}
// End of hack
var validateeProperty = validationContext.ObjectType.GetProperty(memberName);
var validateeType = validateeProperty.PropertyType;
var validatee = validateeProperty.GetValue(validationContext.ObjectInstance, null);
var idParameter = Expression.Constant(id, idType);
var validateeParameter = Expression.Constant(validatee, validateeType);
var objectParameter = Expression.Parameter(validationContext.ObjectType, "o");
var objectIDProperty = Expression.Property(objectParameter, idProperty);
var objectValidateeProperty = Expression.Property(objectParameter, validateeProperty);
var idCheck = Expression.NotEqual(objectIDProperty, idParameter);
var validateeCheck = Expression.Equal(objectValidateeProperty, validateeParameter);
var compositeCheck = Expression.And(idCheck, validateeCheck);
var lambda = Expression.Lambda(compositeCheck, objectParameter);
var countMethod = typeof(Queryable).GetMethods().Single(m => m.Name == "Count" && m.GetParameters().Length == 2);
var genericCountMethod = countMethod.MakeGenericMethod(validationContext.ObjectType);
using (var context = GetDataContext())
{
var table = context.GetTable(validationContext.ObjectType) as IQueryable<Models.Group>;
var count = (int)genericCountMethod.Invoke(null, new object[] { table, lambda });
if (count > 0)
{
return new ValidationResult(Message);
}
}
return null;
}
}
sử dụng Ví dụ:
[MetadataType(typeof(UserMetadata))]
public partial class Group : IDatabaseRecord
{
public class UserMetadata
{
[Required(ErrorMessage = "Name is required")]
[StringLength(255, ErrorMessage = "Name must be under 255 characters")]
[Unique(typeof(MyDataContext), "GroupID", "Name must be unique")]
public string Name { get; set; }
}
}
tôi tình yêu @ giải pháp daveb của. Thật không may, ba năm sau đó nó yêu cầu một số sửa đổi khá nặng đối với tôi. Đây là giải pháp của anh được cập nhật cho EF6. Hy vọng rằng sẽ tiết kiệm một ai đó một giờ hoặc lâu hơn không quan trọng.
public class UniqueAttribute : ValidationAttribute
{
public UniqueAttribute(string idProperty, string message)
{
IdProperty = idProperty;
Message = message;
}
[Inject]
public DataContext DataContext { get; set; }
private string IdProperty { get; set; }
private string Message { get; set; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var objectType = validationContext.ObjectType;
if (objectType.Namespace == "System.Data.Entity.DynamicProxies")
{
objectType = objectType.BaseType;
}
var idProperty = objectType.GetProperty(IdProperty);
var idType = idProperty.PropertyType;
var id = idProperty.GetValue(validationContext.ObjectInstance, null);
var memberName = validationContext.MemberName;
var validateeProperty = objectType.GetProperty(memberName);
var validateeType = validateeProperty.PropertyType;
var validatee = validateeProperty.GetValue(validationContext.ObjectInstance, null);
var idParameter = Expression.Constant(id, idType);
var validateeParameter = Expression.Constant(validatee, validateeType);
var objectParameter = Expression.Parameter(objectType, "o");
var objectIdProperty = Expression.Property(objectParameter, idProperty);
var objectValidateeProperty = Expression.Property(objectParameter, validateeProperty);
var idCheck = Expression.NotEqual(objectIdProperty, idParameter);
var validateeCheck = Expression.Equal(objectValidateeProperty, validateeParameter);
var compositeCheck = Expression.And(idCheck, validateeCheck);
var lambda = Expression.Lambda(compositeCheck, objectParameter);
var countMethod = typeof(Queryable).GetMethods().Single(m => m.Name == "Count" && m.GetParameters().Length == 2);
var genericCountMethod = countMethod.MakeGenericMethod(objectType);
var table = DataContext.Set(objectType);
var count = (int)genericCountMethod.Invoke(null, new object[] { table, lambda });
if (count > 0)
{
return new ValidationResult(Message);
}
return null;
}
}
chỉ làm một cái gì đó như thế này trên mô hình của bạn
[StringLength(100)]
[Index("IX_EntidadCodigoHabilitacion", IsUnique = true)]
public string CodigoHabilitacion { get; set; }
- 1. Ràng buộc duy nhất qua nhiều cột
- 2. Buộc ràng buộc duy nhất trong GAE
- 3. Ràng buộc duy nhất với EFCodeFirst và SqlCe4
- 4. Các ràng buộc duy nhất trong couchdb
- 5. ràng buộc duy nhất có điều kiện
- 6. Ràng buộc duy nhất trên nhiều cột
- 7. JPA - xác định các ràng buộc duy nhất nhiều cột
- 8. Ràng buộc duy nhất với giá trị được xác định
- 9. Ràng buộc dữ liệu với Java
- 10. Làm thế nào để giới thiệu đa cột ràng buộc với chú thích JPA?
- 11. Ràng buộc dữ liệu WinForms
- 12. SQL Server 2005 Ràng buộc duy nhất trên hai cột
- 13. Ràng buộc duy nhất trong kiến trúc RESTFul
- 14. Ràng buộc duy nhất của Oracle và chỉ mục duy nhất
- 15. Ràng buộc bảng SQLite - duy nhất trên nhiều cột
- 16. Tìm xem cột có ràng buộc duy nhất
- 17. Tùy chỉnh chú thích dữ liệu trong dữ liệu động
- 18. Ràng buộc duy nhất có điều kiện trong oracle db
- 19. Tai họa dữ liệu ràng buộc
- 20. kiểm tra ràng buộc duy nhất trong JPA
- 21. MySQL: Ràng buộc duy nhất trên nhiều trường
- 22. Giảm ràng buộc duy nhất cho cột trong H2
- 23. Chiều rộng cột dữ liệu ràng buộc
- 24. Ràng buộc dữ liệu trong NSCollectionView
- 25. WinForms ComboBox dữ liệu ràng buộc Gotcha
- 26. Thực tiễn tốt nhất - Chú thích dữ liệu so với OnChanging trong khung thực thể 4
- 27. Lỗi ràng buộc tải dữ liệu()
- 28. Bộ sưu tập JPA có ràng buộc không mong muốn duy nhất trong bảng ánh xạ
- 29. Ràng buộc dữ liệu với UserControl trong WPF
- 30. javascript tạo khuôn mẫu với các ràng buộc dữ liệu