【问题标题】:How to pass multiple lambda expression in method如何在方法中传递多个 lambda 表达式
【发布时间】:2017-07-11 23:27:41
【问题描述】:

假设我有一个通用的数据访问层方法来更新记录,代码如下:

public virtual void Update<P>(Expression<Func<T, P>> excludeColumn, params T[] items)
{
        foreach (T item in items)
        {
            _entities.Entry(item).State = EntityState.Modified;
            _entities.Entry(item).Property(excludeColumn).IsModified = false;
        }

        _entities.SaveChanges();
}

这里我使用excludeColumn 参数来排除更新中的列,我像这样将值传递给这个参数

_companyProfileRepository.Update(x => x.EmailAddress, records);

x =&gt; x.EmailAddress 是我传递给通用Update 方法的表达式。我的问题是我想将多列传递给Update 方法,因为有时我需要排除不止一列,但我的方法不支持多列机制。

谁能帮我解决这个问题?

【问题讨论】:

  • 我的理解是 EF 已经跟踪你的实体的变化并且只更新修改后的属性,那你为什么需要排除列呢?
  • 因为我发送的是空属性进行更新,即使数据库中有一个值,这样做是因为这是敏感数据,我不想在视图中显示它,但用户可以更新其他值
  • 您可能需要考虑在实体和视图之间添加一个层,例如视图模型 - 请参阅此问题:stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc

标签: c# entity-framework generics lambda


【解决方案1】:

对于多列的情况,您可以添加一个接受未修改列名称的重载。比如:

    public virtual void Update<TEntity>(IEnumerable<string> excludeColumnNames, params TEntity[] items)
    {
        foreach (var item in items)
        {
            _entities.Entry(item).State = EntityState.Modified;
            foreach (var cn in excludeColumnNames)
            {
                _entities.Entry(item).Property(cn).IsModified = false;
            }

        }
        _entities.SaveChanges();
    }

【讨论】:

  • 为什么要继续使用通用存储库反模式? ben-morris.com/…如何正确使用存储库模式:martinfowler.com/eaaCatalog/repository.html
  • 通过泛型类型约束,泛型存储库基类允许代码重用。在为不同(但非常相似)的表实现存储库时,我发现它非常有用。
  • 除非重用会在您发现一个表的更新方法与另一个表的更新方法不同的那一刻中断,顺便说一下,这是 OP 刚刚遇到的问题。
  • 没有任何问题 - 如果需要,您可以使更新方法成为抽象或虚拟方法,在派生类中实现。我正在查看以这种方式编写的通用存储库。
【解决方案2】:

使用存储库模式,您可以将 EF 数据层包装在具有实际意义的东西中,而不是隐藏意图的通用/抽象代码。 网络上有大量通用实现的存储库模式示例,但我认为这是一种反模式,and I'm not alone

例如UserProfileRepository 可以有这样的接口:

public interface IUserProfileRepository
{
  void UpdateUserProfile(IUserProfile p);
}

这种抽象对于任何阅读您的代码的人来说都是有意义的,因为它清楚地表明了它的意图。此外,上述代码更改的唯一原因是,如果您存储 IUserProfile 的方式实际上发生了变化,并且如果您在更新 UserProfile 时需要进行一些特殊处理,那么您可以在某个地方放置它。

比较你的:

void Update<TEntity>(IEnumerable<string> excludeColumnNames, params TEntity[] items)

当调用此方法以实现许多不同的结果时,这会掩盖其含义,并且如果有更新特定实体类型的特殊处理,则您无处可放,因此最终会被推上一层并在每次需要时复制。

还要考虑获取实体和更新实体是两个非常不同的操作。您可能会获得实体的所有属性,但只更新其中一些属性,我相信您在问题中指的是这些属性。我认为 EF 使对实体的读写“感觉”几乎相同的方式是一种可怕的抽象,会导致大量的痛苦和折磨。正如CQRS pattern 所证明的那样,读取和写入数据是非常不同的用例。

【讨论】:

    【解决方案3】:

    如果你想传入多个列,那么将它们传入...
    数组或列表是常用的方式。

    public virtual void Update<P>(List<Expression<Func<T, P>>> excludeColumns, params T[] items)
    {
         foreach (T item in items)
         {
             foreach (Expression<Func<T, P>> excludeColumn in excludeColumns)
             {
                _entities.Entry(item).State = EntityState.Modified;
                _entities.Entry(item).Property(excludeColumn).IsModified = false;       
             }
         }
    
        _entities.SaveChanges();
    }
    

    只要每列的 P 类型相同就可以了。

    【讨论】:

      【解决方案4】:

      我有类似的方法,但使用的是 linq-to-sql。这是一种有点不同的方法,但效果很好。您可能需要对其进行调整以与 EF 一起使用。

      public class Data
      {
          public static void Update<T>(Func<T, bool> where, Action<T> change)
          {
              IEnumerable<T> items = ((IEnumerable<T>)myDataContext.GetTable(typeof(T))).Where(where);
      
              foreach (T item in items)
              {
                  change(item);
              }
      
              myDataContext.SubmitChanges();
          }
      }
      

      我是这样使用的:

      Data.Update<User>(u => u.Id == 3, u =>
      {
          u.Name = "John";
          u.Age = 25;
          u.Email = "john@email.com";
      });
      

      虽然这可能不是对这个问题的直接回答,但我相信这是相关的并且会有所帮助。

      【讨论】:

      • myDataContext 来自哪里 - 它的范围是什么?为什么是静态 Update() 方法?这是什么模式 - 它似乎是一个“静态通用存储库”anitpattern!
      • @saille 这只是示例代码。应根据用户配置、连接字符串等创建数据上下文。此外,这无关紧要,因为它在 EF 中有所不同。此外,它是减少重复代码的简单助手,仅在有意义时才应使用。它没有任何问题,除非有人滥用它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 1970-01-01
      • 1970-01-01
      • 2019-05-07
      • 2018-01-29
      • 1970-01-01
      相关资源
      最近更新 更多