При использовании хранилища возможно ли для типа возвращать Func, который хранилище использует для проверки существующих сущностей? - PullRequest
1 голос
/ 12 января 2011

Например, для фабрики с методом

public static T Save<T>(T item) where T : Base, new()
{
  /* item.Id == Guid.Empty therefore item is new */
  if (item.Id == Guid.Empty && repository.GetAll<T>(t => t.Name == item.Name))
  {
    throw new Exception("Name is not unique");
  }
}

как мне создать свойство Base (скажем, MustNotAlreadyExist), чтобы я мог изменить приведенный выше метод на

public static T Save<T>(T item) where T : Base, new()
{
  /* item.Id == Guid.Empty therefore item is new */
  if (item.Id == Guid.Empty && repository.GetAll<T>(t.MustNotAlreadyExist))
  {
    throw new Exception("Name is not unique");
  }
}

public class Base
{
  ...
  public virtual Expression<Func<T, bool>> MustNotAlreadyExist()
  {
    return (b => b.Name == name); /* <- this clearly doesn't work */
  }
}

и как я могу переопределить MustNotAlreadyExist в Account : Base

public class Account : Base
{
  ...
  public override Expression<Func<T, bool>> MustNotAlreadyExist()
  {
    return (b => b.Name == name && b.AccountCode == accountCode); /* <- this doesn't work */
  }
  ...
}

Ответы [ 3 ]

2 голосов
/ 12 января 2011

Попробуйте это:

public class Account : Base
{
  ...
  public override Expression<Func<T, bool>> MustNotAlreadyExist()
  {
    return (b => b.Name == name && b.AccountCode == accountCode).Any();
  }
  ...
}

Метод Any () вернет true, если какая-либо запись соответствует предикату. Можно утверждать, что репозиторий не несет ответственности за проверку наличия записи перед сохранением.

UPDATE:
На CodeProject есть отличная статья, в которой описывается общий репозиторий для Entity Framework:

http://www.codeproject.com/KB/database/ImplRepositoryPatternEF.aspx

Это может быть применено к контексту данных не-Entity Framework. Вот выдержка, которая обеспечивает очень гибкий метод для проверки существующего значения, принимая имя поля, значение и значение ключа. Вы можете применить это к любому типу сущности и использовать его для проверки наличия сущности перед попыткой сохранения.

/// <summary>
    /// Check if value of specific field is already exist
    /// </summary>
    /// <typeparam name="E"></typeparam>
    /// <param name="fieldName">name of the Field</param>
    /// <param name="fieldValue">Field value</param>
    /// <param name="key">Primary key value</param>
    /// <returns>True or False</returns>
    public bool TrySameValueExist(string fieldName, object fieldValue, string key)
    {
        // First we define the parameter that we are going to use the clause. 
        var xParam = Expression.Parameter(typeof(E), typeof(E).Name);
        MemberExpression leftExprFieldCheck = 
        MemberExpression.Property(xParam, fieldName);
        Expression rightExprFieldCheck = Expression.Constant(fieldValue);
        BinaryExpression binaryExprFieldCheck = 
        MemberExpression.Equal(leftExprFieldCheck, rightExprFieldCheck);

        MemberExpression leftExprKeyCheck = 
        MemberExpression.Property(xParam, this._KeyProperty);
        Expression rightExprKeyCheck = Expression.Constant(key);
        BinaryExpression binaryExprKeyCheck = 
        MemberExpression.NotEqual(leftExprKeyCheck, rightExprKeyCheck);
        BinaryExpression finalBinaryExpr = 
        Expression.And(binaryExprFieldCheck, binaryExprKeyCheck);

        //Create Lambda Expression for the selection 
        Expression<Func<E, bool>> lambdaExpr = 
        Expression.Lambda<Func<E, bool>>(finalBinaryExpr, 
        new ParameterExpression[] { xParam });
        //Searching ....            
        return ((IRepository<E, C>)this).TryEntity(new Specification<E>(lambdaExpr));
    }
    /// <summary>
    /// Check if Entities exist with Condition
    /// </summary>
    /// <param name="selectExpression">Selection Condition</param>
    /// <returns>True or False</returns>
    public bool TryEntity(ISpecification<E> selectSpec)
    {
        return _ctx.CreateQuery<E>("[" + typeof(E).Name + "]").Any<E>
                    (selectSpec.EvalPredicate);
    }
1 голос
/ 12 января 2011

Я не уверен, что ваша проблема разрешима, так как вам нужен доступ как к хранилищу, так и к новому элементу, который нужно проверить. Новый проверяемый элемент недоступен в отдельном методе.

Однако вы можете передать вызов GetAll на внешний подряд, чтобы ваш код стал похож на (не проверено)

public static T Save<T>(T item) where T : Base, new()
{
  if (item.Id == Guid.Empty && (Check(repository, item)))
  {
    throw new Exception("Name is not unique");
  }
}

public class Base
{
  ...
  public Func<Enumerable<T>, T, bool> Check { get; set;}

  public Base()
  {
    Check = (col, newItem) => (null != col.FirstOrDefault<T>(
                                       item => item.Name == newItem.Name));
  }
}
0 голосов
/ 13 января 2011

Хорошо, вот ответ, это комбинация кода, опубликованного Дейвом Сверски, и немного, но здравого смысла.

public interface IUniqueable<T>
{
  Expression<Func<T, bool>> Unique { get; }
}

public class Base, IUniqueable<Base>
{
  ...
  public Expression<Func<Base, bool>> Unique
  {
    get
    {
      var xParam = Expression.Parameter(typeof(Base), typeof(Base).Name);
      MemberExpression leftExprFieldCheck = MemberExpression.Property(xParam, "Name");
      Expression rightExprFieldCheck = Expression.Constant(this.Name);
      BinaryExpression binaryExprFieldCheck = MemberExpression.Equal(leftExprFieldCheck, rightExprFieldCheck);
      return Expression.Lambda<Func<Base, bool>>(binaryExprFieldCheck, new ParameterExpression[] { xParam });
    }
  }
  ...
}

public class Account : Base, IUniqueable<Account>
{
  ...
  public new Expression<Func<Account, bool>> Unique
  {
    get
    {
      var xParam = Expression.Parameter(typeof(Account), typeof(Account).Name);
      MemberExpression leftExprNameCheck = MemberExpression.Property(xParam, "Name");
      Expression rightExprNameCheck = Expression.Constant(this.Name);
      BinaryExpression binaryExprNameCheck = MemberExpression.Equal(leftExprNameCheck, rightExprNameCheck);

      MemberExpression leftExprFieldCheck = MemberExpression.Property(xParam, "AccountCode");
      Expression rightExprFieldCheck = Expression.Constant(this.AccountCode);
      BinaryExpression binaryExprFieldCheck = MemberExpression.Equal(leftExprFieldCheck, rightExprFieldCheck);

      BinaryExpression binaryExprAllCheck = Expression.OrElse(binaryExprNameCheck, binaryExprFieldCheck);

      return Expression.Lambda<Func<Account, bool>>(binaryExprAllCheck, new ParameterExpression[] { xParam });
    }
  }
  ...
}

public static class Manager
{
  ...
  public static T Save<T>(T item) where T : Base, new()
  {
    if (!item.IsValid)
    {
      throw new ValidationException("Unable to save item, item is not valid", item.GetRuleViolations());
    }

    if (item.Id == Guid.Empty && repository.GetAll<T>().Any(((IUniqueable<T>)item).Unique))
    {
      throw new Exception("Item is not unique");
    }

    return repository.Save<T>(item);
  }
  ...
}

По сути, реализуя интерфейс IUniqueable для определенного типа, я могу вернуть разные Expression для каждого типа. Все хорошо: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...