私は実際にZ.EntityFramework.Plusバルク更新の周りのラッパーである次の関数を持っています:
public static int UpdateBulk<T>(this IQueryable<T> query, Expression<Func<T, T>> updateFactory) where T : IBaseEntity, new()
{
Expression<Func<T, T>> modifiedExpression = x => new T() { ModifiedBy = "Test", ModifiedDate = DateTime.Now };
var combine = Expression.Lambda<Func<T, T>>(
Expression.AndAlso(
Expression.Invoke(updateFactory, updateFactory.Parameters),
Expression.Invoke(modifiedExpression, modifiedExpression.Parameters)
),
updateFactory.Parameters.Concat(modifiedExpression.Parameters)
); //This returns an error
return query.Update(combine);
}
このように呼び出された:
decimal probId = ProbId.ParseDecimal();
db.Problems
.Where(e => e.ProbId == probId)
.UpdateBulk(e => new Problem() {
CatId = Category.ParseNullableInt(),
SubCatId = SubCategory.ParseNullableInt(),
ListId = Problem.ParseNullableInt()
});
IBaseEntityは次のように定義されます。
public abstract class IBaseEntity
{
public System.DateTime CreatedDate { get; set; }
public string CreatedBy { get; set; }
public System.DateTime ModifiedDate { get; set; }
public string ModifiedBy { get; set; }
public string DeletedBy { get; set; }
}
IBaseEntityを実装する方法で 'Problem'クラス。
私がやりたいことは、UpdateBulk関数のupdateFactoryにModifiedByとModifiedDateを自動的に追加して、UpdateBulkを呼び出すたびに実行する必要がないようにすることです。
私は、上記のUpdateBulk関数を使って、解析された 'updateFactory'式と 'modifiedExpression'を組み合わせようとしましたが、エラーを返します:
バイナリ演算子AndAlsoは 'Problem'型に対して定義されていません。
このようにExpressionをマージすることは可能ですか?もしそうなら、私は何が間違っていますか?そうでない場合、どのようにしてModifiedBy = "Test"、ModifiedDate = DateTime.NowをupdateFactory式にマージできますか?
ありがとう、ロッド
これはBinaryExpression - Expression<Func<T,bool>>
意味するので、 AndAlso
使用することはできません。この場合、 Marc Gravellによってここで定義されている Expression Visitorが必要です (したがって、
私はProblem class schema
、Linqpadコードを貼り付けることの前提で、あなたのケースで解決策を提供するために同じを使用しています:
void Main()
{
var final = UpdateBulk((Problem p) => new Problem{CatId = 1,SubCatId = 2, ListId=3});
// final is of type Expression<Func<T,T>>, which can be used for further processing
final.Dump();
}
public static Expression<Func<T, T>> UpdateBulk<T>(Expression<Func<T, T>> updateFactory) where T : IBaseEntity, new()
{
Expression<Func<T, T>> modifiedExpression = x => new T() { ModifiedBy = "Test", ModifiedDate = DateTime.Now };
var result = Combine(updateFactory, modifiedExpression);
return result;
}
static Expression<Func<TSource, TDestination>> Combine<TSource, TDestination>(
params Expression<Func<TSource, TDestination>>[] selectors)
{
var param = Expression.Parameter(typeof(TSource), "x");
return Expression.Lambda<Func<TSource, TDestination>>(
Expression.MemberInit(
Expression.New(typeof(TDestination).GetConstructor(Type.EmptyTypes)),
from selector in selectors
let replace = new ParameterReplaceVisitor(
selector.Parameters[0], param)
from binding in ((MemberInitExpression)selector.Body).Bindings
.OfType<MemberAssignment>()
select Expression.Bind(binding.Member,
replace.VisitAndConvert(binding.Expression, "Combine")))
, param);
}
class ParameterReplaceVisitor : ExpressionVisitor
{
private readonly ParameterExpression from, to;
public ParameterReplaceVisitor(ParameterExpression from, ParameterExpression to)
{
this.from = from;
this.to = to;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node == from ? to : base.VisitParameter(node);
}
}
public abstract class IBaseEntity
{
public System.DateTime CreatedDate { get; set; }
public string CreatedBy { get; set; }
public System.DateTime ModifiedDate { get; set; }
public string ModifiedBy { get; set; }
public string DeletedBy { get; set; }
}
public class Problem : IBaseEntity
{
public int CatId { get; set; }
public int SubCatId { get; set; }
public int ListId { get; set; }
}