.net泛型方法,带参数IQueryable <t>和表达式<func <t,t =“”>&gt;

时间:2016-07-26 22:48:16

标签: c# entity-framework expression iqueryable

我想为此函数创建一个泛型方法,并发送用户类和where子句,如参数。

public void Update(where clause, User user) {}

但我找不到正确的方法。

ctx.Users.Where(x => x.Id == 10)
         .Update(x => new User() { Name = "Jack" });

方法声明是:

public static int Update<T>(this IQueryable<T> query, Expression<Func<T, T>> updateFactory) where T : class;

1 个答案:

答案 0 :(得分:0)

如果您传递已创建的User实例,Update方法将无法知道要更新哪些属性(例如,是否应更新所有属性?或者具有非默认值的属性) ?如果故意将财产设置为默认值怎么办?)。

您需要传递包含成员初始化表达式的Expression<Func<T, T>>表达式,例如x => new User() { Name = "Jack" }

表达式是代码作为数据。在框架内部,框架将解析表达式并查看要更新的属性。在示例的情况下,它将看到仅更新Name属性。

至于where表达式,您需要传递Expression<Func<User,bool>>。所以你的方法看起来像这样:

public void Update(
    Expression<Func<User,bool>> condition,
    Expression<Func<User,User>> updateFactory)
{
    ctx.Users
       .Where(condition)
       .Update(updateFactory);
}

你可以像这样使用它:

Update(x => x.Id == 10, x => new User() { Name = "Jack" });

修改

如果您有办法找到要更新的属性,可以构建如下表达式:

public static void Update(
    Expression<Func<User, bool>> condition,
    User user,
    PropertyInfo[] propertiesToUpdate)
{
    Expression<Func<User, User>> updateFactory =
        Expression.Lambda<Func<User, User>>(
            Expression.MemberInit(
                Expression.New(typeof (User)),
                propertiesToUpdate
                    .Select(prop =>
                        Expression.Bind(
                            prop.SetMethod,
                            Expression.Constant(prop.GetValue(user))))),
            Expression.Parameter(typeof(User), "u"));

    ctx.Users
        .Where(condition)
        .Update(updateFactory);
}

如果您只有属性名称,则可以使用Type.GetProperty方法获取相应的PropertyInfo