使用存储库时,类型是否可以返回存储库用于测试现有实体的 Func?

发布于 2024-10-12 06:24:39 字数 1196 浏览 8 评论 0原文

例如,给定一个具有方法的工厂,

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在帐户:基础

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

For example given a Factory with a method

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

how do I create a property of Base (say MustNotAlreadyExist) so that I can change the method above to

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 */
  }
}

and then how can I override MustNotAlreadyExist in 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 */
  }
  ...
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

转角预定愛 2024-10-19 06:24:39

试试这个:

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

如果任何记录与谓词匹配,Any() 方法将返回 true。可能有人会说,在保存之前检查记录是否存在不属于存储库的责任。

更新:
CodeProject 上有一篇很棒的文章,描述了实体框架的通用存储库:

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

这可以应用于非实体框架数据上下文。以下摘录提供了一种非常灵活的方法,通过接受字段名称、值和键值来检查现有值。您可以将此应用于任何实体类型,并在尝试保存之前使用它来检查实体是否存在。

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

Try this:

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

The Any() method will return true if any record matches the predicate. It could be argued that it is outside the responsibility of the repository to check for presence of a record before saving.

UPDATE:
There is a great article on CodeProject that describes a generic Repository for Entity Framework:

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

This could be applied to a non-Entity Framework data context. Here is an excerpt that provides a very flexible method for checking for an existing value by accepting the name of a field, a value, and a key value. You can apply this to any Entity type and use it to check for the presence of an entity before attempting a save.

/// <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);
    }
素手挽清风 2024-10-19 06:24:39

我不确定您的问题是否可以解决,因为您需要访问存储库和要检查的新项目。要检查的新项目在单独的方法中不可用。

但是,您可以将调用外包给 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));
  }
}

I am not shure if you problem is solvable since you need to access both the repository and the new item to be checked. The new item to be checked is not available in a seperate method.

However you can outsource the call to GetAll so that your code becomes something similar to
(not tested)

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));
  }
}
再浓的妆也掩不了殇 2024-10-19 06:24:39

好的,这就是答案,这是 Dave Swersky 发布的代码和一些常识的组合。

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 接口,我可以为每种类型返回不同的表达式。一切都好:-)

OK, here is the answer, this is a combination of the code posted by Dave Swersky and a little but of common sense.

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

Essentially by implementing the IUniqueable interface for a specific type I can return a different Expression for each type. All good :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文