Как использовать лямбда-выражение для реализации UniqueAttribute?

Я просто хочу использовать подобный код для реализации атрибута проверки клиента с именем UniqueAttribute в MVC, но я не очень хорошо знаю о выражении lamda.

Класс редактирования модели

Класс UniqueAttribute:

    public class UniqueAttribute<TService,TEntity,TKey> : ValidationAttribute
    where TService : IDML<TEntity>
    where TEntity:IPMMIdentity
{
    public Expression<Func<TEntity, TKey>> UniqueExpression { get; set; }

    public override bool IsValid(object value)
    {
        var service = IocContainerHelper.Resolve<TService>();
        return !service.Contains(UniqueExpression, (TKey)value);
    }
}

Я создал метод "Содержит" в моем классе, где реализует интерфейс IDML:

        public virtual bool Contains<TKey>(Expression<Func<T, TKey>> selector, TKey value)
    {
        var predicate = Expression.Lambda<Func<T, bool>>(
            Expression.Equal(selector.Body, Expression.Constant(value, typeof(TKey)))
            , selector.Parameters);

        return _repository.Count(predicate)>0;
    }

Поэтому я хочу определить свою модель редактирования, как показано ниже:

public class EditUser
{
    public int Id { get; set; }

    [Unique<IUserService,User,string>(UniqueExpression = t=>t.LoginName)] // error line,can not be complied.
    public string LoginName { get; set; }
}

Сообщение об ошибке:

Cannot convert source type 'System.Linq.Expression.Expression<System.Func<User,string>>' to target type 'System.Linq.Expression.Expression<System.Func<TEntity,TKey>>'

Как это исправить? Любая помощь будет высоко ценится, спасибо.

ОБНОВИТЬ:

Я изменил класс проверки, и он работает хорошо.

public class UniqueAttribute:ValidationAttribute
{
    public UniqueAttribute(Type serviceType, Type entityType, string propertyName)
    {
        ServiceType = serviceType;
        EntityType = entityType;
        PropertyName = propertyName;
    }

    public Type ServiceType { get; private set; }
    public Type EntityType { get; private set; }
    public string PropertyName { get; private set; }

    protected override ValidationResult IsValid(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext)
    {
        var propertyInfo = EntityType.GetProperty(PropertyName);
        const string methodName = "Get";

        object convertedValue = Convert.ChangeType(value, propertyInfo.PropertyType);
        var constExpression = Expression.Constant(convertedValue);

        var parameter = Expression.Parameter(EntityType, "te");
        var memberExpression = Expression.MakeMemberAccess(parameter, propertyInfo);
        var equal = Expression.Equal(memberExpression, constExpression);
        var lambda = Expression.Lambda(equal, parameter);

        var service = IocContainerHelper.Resolve(ServiceType);

        const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public;
        var method = service.GetType().GetMethod(methodName, bindingFlags);

        if (method == null)
        {
            throw new NullReferenceException(string.Format("{0} have not suitable method named '{1}'", service.GetType().FullName, methodName));
        }

        object id = validationContext.ObjectInstance.GetId();
        object data = method.Invoke(service, new object[] { lambda });

        if (!data.GetId().Equals(id))
        {
            var errorMessage = string.Format("{0} is used。", convertedValue);
            return new ValidationResult(errorMessage);
        }
        return ValidationResult.Success;
    }

Экземпляр ServiceType реализует метод Get(Expression> condition):

    public virtual T Get(Expression<Func<T, bool>> condition)
    {
        return _repository.Get(condition);
    }

В редактируемой модели он используется как:

    [Required]
    [Unique(typeof(IUserService),typeof(User),"LoginName")]
    [StringLength(50)]
    [Display(Name = "Login Name")]
    public string LoginName { get; set; }

Надеюсь, это поможет вам.

0 ответов

Другие вопросы по тегам