Dal*_*yKD 6 c# lambda expression-trees linq-to-sql
LINQ-to-SQL一直是我的PITA.我们使用它与数据库进行通信,然后通过WCF将实体发送到Silverlight应用程序.一切都运行正常,直到开始编辑(CUD)实体及其相关数据.
我终于能够设计两个允许CUD的for循环.我试着重构它们,而我非常接近,直到我得知我不能总是用L2S做Lambda.
public static void CudOperation<T>(this DataContext ctx, IEnumerable<T> oldCollection, IEnumerable<T> newCollection, Func<T, T, bool> predicate)
where T : class
{
foreach (var old in oldCollection)
{
if (!newCollection.Any(o => predicate(old, o)))
{
ctx.GetTable<T>().DeleteAllOnSubmit(ctx.GetTable<T>().Where(o => predicate(old, o)));
}
}
foreach (var newItem in newCollection)
{
var existingItem = oldCollection.SingleOrDefault(o => predicate(o, newItem));
if (existingItem != null)
{
ctx.GetTable<T>().Attach(newItem, existingItem);
}
else
{
ctx.GetTable<T>().InsertOnSubmit(newItem);
}
}
}
Run Code Online (Sandbox Code Playgroud)
被称为:
ctx.CudOperation<MyEntity>(myVar.MyEntities, newHeader.MyEntities,
(x, y) => x.PkID == y.PkID && x.Fk1ID == y.Fk1ID && x.Fk2ID == y.FK2ID);
Run Code Online (Sandbox Code Playgroud)
这几乎奏效了.但是,我的Func需要是一个表达式>,这就是我被困的地方.
有没有人可以告诉我这是否可能?由于SharePoint 2010,我们必须使用.NET 3.5.
por*_*ges 11
只需更改参数:
Func<T, T, bool> predicate
Run Code Online (Sandbox Code Playgroud)
至:
Expression<Func<T, T, bool>> predicate
Run Code Online (Sandbox Code Playgroud)
表达式由编译器生成.
现在,问题是如何使用它.
在您的情况下,您需要a Func 和 a Expression,因为您在EnumerableLINQ查询(基于func)以及SQL LINQ查询(基于表达式)中使用它.
在:
.Where(o => predicate(old, o))
Run Code Online (Sandbox Code Playgroud)
该old参数是固定的.所以我们可以将参数更改为:
Func<T, Expression<Func<T, bool>>> predicate
Run Code Online (Sandbox Code Playgroud)
这意味着我们可以提供一个参数('固定'一个)并返回一个表达式.
foreach (var old in oldCollection)
{
var condition = predicate(old);
// ...
{
ctx.GetTable<T>().DeleteAllOnSubmit(ctx.GetTable<T>().Where(condition));
}
}
Run Code Online (Sandbox Code Playgroud)
我们还需要使用它Any.要从表达式获取Func,我们可以调用Compile():
foreach (var old in oldCollection)
{
var condition = predicate(old);
if (!newCollection.Any(condition.Compile()))
{
ctx.GetTable<T>().DeleteAllOnSubmit(ctx.GetTable<T>().Where(condition));
}
}
Run Code Online (Sandbox Code Playgroud)
你可以用下一部分做同样的事情.
有两个问题:
Compile()批次可能会影响性能.我不确定它实际会产生多大的影响,但我会对其进行分析以进行检查.(x,y) => ...你将是通过x => y => ....我不确定这对你来说是不是很重要.可能有更好的方法来做到这一点:)
这是另一种方法,它应该更快一些,因为Expression只需要编译一次.创建一个"应用"一个参数的重写器,如下所示:
class PartialApplier : ExpressionVisitor
{
private readonly ConstantExpression value;
private readonly ParameterExpression replace;
private PartialApplier(ParameterExpression replace, object value)
{
this.replace = replace;
this.value = Expression.Constant(value, value.GetType());
}
public override Expression Visit(Expression node)
{
var parameter = node as ParameterExpression;
if (parameter != null && parameter.Equals(replace))
{
return value;
}
else return base.Visit(node);
}
public static Expression<Func<T2,TResult>> PartialApply<T,T2,TResult>(Expression<Func<T,T2,TResult>> expression, T value)
{
var result = new PartialApplier(expression.Parameters.First(), value).Visit(expression.Body);
return (Expression<Func<T2,TResult>>)Expression.Lambda(result, expression.Parameters.Skip(1));
}
}
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它:
public static void CudOperation<T>(this DataContext ctx,
IEnumerable<T> oldCollection,
IEnumerable<T> newCollection,
Expression<Func<T, T, bool>> predicate)
where T : class
{
var compiled = predicate.Compile();
foreach (var old in oldCollection)
{
if (!newCollection.Any(o => compiled(o, old)))
{
var applied = PartialApplier.PartialApply(predicate, old);
ctx.GetTable<T>().DeleteAllOnSubmit(ctx.GetTable<T>().Where(applied));
}
}
foreach (var newItem in newCollection)
{
var existingItem = oldCollection.SingleOrDefault(o => compiled(o, newItem));
if (existingItem != null)
{
ctx.GetTable<T>().Attach(newItem, existingItem);
}
else
{
ctx.GetTable<T>().InsertOnSubmit(newItem);
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2068 次 |
| 最近记录: |