LINQ-to-SQL has been a PITA for me. We’re using it to communicate to the database, and then send entities via WCF to a Silverlight app. Everything was working fine, until it came time to start editing (CUD) the entities, and their related data.
I was finally able to devise two for loops that allowed the CUD. I tried to refactor them, and I was so close, until I learned that I can’t always do Lambda with L2S.
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);
}
}
}
Called by:
ctx.CudOperation<MyEntity>(myVar.MyEntities, newHeader.MyEntities,
(x, y) => x.PkID == y.PkID && x.Fk1ID == y.Fk1ID && x.Fk2ID == y.FK2ID);
This almost worked. However, my Func needs to be an Expression>, and that’s where I’m stuck.
Is there anyone who can tell me if this is possible? We have to be in .NET 3.5 due to SharePoint 2010.
Just change the parameter from:
To:
The Expression is generated by the compiler.
Now, the issue is how to use this.
In your case, you need both a
Funcand anExpression, since you’re using it inEnumerableLINQ queries (func based) as well as the SQL LINQ queries (expression based).In:
The
oldparameter is fixed. So we could change the parameter to:This means we can supply one argument (the ‘fixed’ one) and get back an expression.
We also need to use this in
Any. To get a Func from an Expression we can callCompile():You can do the same thing with the next part.
There are two issues:
Compile()lots. I’m not sure how much effect it would actually have, but I’d profile it to check.(x,y) => ...you will be passingx => y => .... I’m not sure if this is a big deal for you.There might be a better way to do this 🙂
Here’s an alternate method, which should be a bit faster, since the Expression only has to be compiled once. Create a rewriter that will ‘apply’ one argument, like this:
Then use it like this: