简体   繁体   English

如何在方法中传递多个Lambda表达式

[英]How to pass multiple lambda expression in method

Suppose I have a generic data access layer method for updating records with something like this code: 假设我有一个通用的数据访问层方法,用于使用以下代码更新记录:

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

Here I am taking excludeColumn param for excluding column from update, and I passed value into this parameter like this 在这里,我采用excludeColumn参数来从更新中排除列,并且像这样将值传递给此参数

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

x => x.EmailAddress is an expression which I pass into the generic Update method. x => x.EmailAddress是一个表达式,我将其传递给通用的Update方法。 My problem is I want to pass multiple columns into Update method, because sometimes I need to exclude more than just one column, but my method doesn't support multiple column mechanism. 我的问题是我想将多个列传递给Update方法,因为有时我需要排除多个列,但我的方法不支持多列机制。

Can anyone help me figure this out? 谁能帮我解决这个问题?

For the multiple-column case, you could add an overload that accepts the names of unmodified columns. 对于多列情况,您可以添加一个重载,该重载接受未修改的列的名称。 Something like: 就像是:

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

Using the Repository Pattern you can wrap your EF data layer in something that actually has meaning, rather than generic/abstract code that conceals intention. 使用存储库模式,您可以将EF数据层包装在实际上具有含义的东西中,而不是隐藏意图的通用/抽象代码中。 There are tons of examples on the web of Repository Pattern implemented generically, but I consider this an anti-pattern, and I'm not alone . 在Repository Pattern的网络上有大量的示例,这些示例是通用实现的,但我认为这是一种反模式, 我并不孤单

eg a UserProfileRepository could have an interface like this: 例如,UserProfileRepository可以具有如下接口:

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

This is the kind of abstraction that makes sense to anyone reading your code because it makes its intent clear. 对于任何阅读您的代码的人来说,这种抽象都是有意义的,因为它可以使意图明确。 Furthermore, the only reason for the above code to change is if there is actually a change to the way you are storing IUserProfile, and if you have some special handling to do when updating UserProfile, you have somewhere to put it. 此外,更改上述代码的唯一原因是,实际上是否更改了存储IUserProfile的方式,并且如果在更新UserProfile时要进行一些特殊处理,则可以在其中放置它。

Compare your: 比较您的:

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

which obscures meaning when calls to this method are sprinkled around your code to achieve many different outcomes, and if there's special handling for updating a specific entity type, you have nowhere to put it, so it ends up getting pushed up a layer and duplicated every time its needed. 当将这种方法的调用散布在代码周围以实现许多不同的结果时,这会掩盖含义,并且如果对更新特定实体类型进行了特殊处理,则无处放置它,因此最终将其推上一层并重复时间需要。

Also consider that getting an entity and updating it are two very different operations. 还要考虑获取实体和更新实体是两个非常不同的操作。 You might get all properties on an entity, but only update some of them, which I believe you are referring to in your question. 您可能会获得一个实体的所有属性,但只能更新其中的一些属性,我相信您在问题中所指的是这些属性。 I consider the way EF makes read and writes to entities 'feel' almost the same to be an awful abstraction that leads to a great deal of pain and suffering. 我认为EF使实体“感觉”到读写的方式几乎是一种可怕的抽象,导致大量的痛苦和折磨。 Reading and writing data are very distinct use cases, as the CQRS pattern proves. 正如CQRS模式所证明的,读写数据是非常不同的用例。

If you want to pass multiple columns in, then pass them in... 如果要传入多个列,则将它们传入...
Arrays or lists are the usual way. 数组或列表是通常的方法。

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

That'll be fine as long as each column has the same type P. 只要每个列都具有相同的类型P,就可以了。

I have a similar method, but using linq-to-sql. 我有类似的方法,但是使用linq-to-sql。 It's a bit different approach, but this works very well. 这是一种不同的方法,但是效果很好。 You may need to adapt it to use with EF. 您可能需要对其进行调整以与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();
    }
}

I use it like this: 我这样使用它:

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

While this may not be a direct answer to this question, I believe this is relevant and will help. 尽管这可能不是对这个问题的直接答案,但我相信这是相关的并且会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM