Linq to SQL Dynamic Where Clause - vb.net

I have a simple query:
dim res = (From x In db.INVENTORies
Where x.INVENTORY_ACTIVATION_DATE IsNot Nothing).count
I need to run this for 14 different date fields, so how do I run this where INVENTORY_ACTIVATION_DATE can be a variable/dynamic?
something like:
function GetCount(aField as string) as integer
return (From x In db.INVENTORies
Where x.**<Use aField here>** IsNot Nothing).count
end function
Thanks in advance.
Steve
I've tried Dynamic Linq and PredicateBuilder, but there are no good examples for my scenario.

C# Eval Expression
Disclaimer: I'm the owner of the project C# Eval Expression
The library is not free, but you can do pretty much any dynamic LINQ using the same syntax as C#.
So it can be used in your VB.NET application, but you will need to use C# syntax for the dynamic part
return context.Customers.WhereDynamic("x => x.AnyField != null && x.AnyField2 != null").count
As you can see, you simply need to create the string to execute dynamically.
LINQ Dynamic
https://www.nuget.org/packages/System.Linq.Dynamic.Core/
The same can be achieved with LINQ Dynamic. You can find some where example here
You don't have to use the PredicateBuilder but simply create the string dynamically.

Through much trail and error, I finally got this working. I ended up using System.Linq.Dynamic.Core.

Related

Is there a way to do something similar to IIF(condition, trueValue, falseValue) within a linq statement?

I am trying to return a string if a property is null in my linq entity framework query when pulling from the database.
select new with { .StringOnlyProp = IIF(x.PossiblyNull Is Nothing, "", x.PossiblyNull)
This throws an error stating that linq cant interpret IIF.
I believe c# syntax is similar to x.PossiblyNull ?? ""
I am hoping VB.NET has something similar.
For a general case you can have:
value = If(<test>, <true result>, <false result>);
this is similar to what you already have, except that IIF evaluates both return values (which is an easy source of bugs). It is the vb.net equivalent of the following:
value = <test> ? <true result> : <false result>;
For the shortcut version of a null test you have the null-coalescing operator:
value = If(PossiblyNull,<result if null>)
This is the vb.net version of:
value = <test> ?? <result if null>;
Watch out though - depending on what you're doing with your linq you may still have problems if the linq cannot be converted to a database query.
I believe the VB equivalent of C#s ?? operator is If. For example, you just need to remove a single letter form your example:
If(x.PossiblyNull Is Nothing, "", x.PossiblyNull)
Or as pointed out by #Glorin in the comments, use the two argument version of the If function for null coalescing:
If(x.PossiblyNull Is Nothing, "")

How get selected listitems using linq - lambda syntax?

I'm using VB.Net and I would like to know how to get the selected checkboxes in a checkboxlist using linq and lambda syntax (not query syntax, repeat NO query syntax).
I tried this but it's definitely not right.
cblRequired.Items.OfType(Of ListItem).Where(Function (i As ListItem ) i.Selected End Function)
I believe that the only thing wrong with your code is that you should not have the End Function, since it's a single-line lambda expression. This should work:
cblRequired.Items.OfType(Of ListItem).Where(Function(i As ListItem) i.Selected)
Technically, you don't need to specify the type of i, since it will automatically infer the type:
cblRequired.Items.OfType(Of ListItem).Where(Function(i) i.Selected)
If you want it to be a multi-line lamba expression, that would look like this:
cblRequired.Items.OfType(Of ListItem).Where(Function(i)
Return i.Selected
End Function)

VB.Net and Linq syntax with regards to bracketing

I have the following code that works fine in VB.net ( VS 2012 ). Note that m.Listen is returning an IObservable(of Maybe(of NominalObject))
Dim d As IDisposable = (From x In m.Listen(Of Maybe(Of NominalObject))()
From y In x
Select New LAPViewCommands(y)).
BindToControl(Me, Function(x) x.ViewModel)
d.DisposeWith(Me)
This is part of a custom user control and I have some extension methods for
binding IObservables to models. However the details are irrelevant. When
I change the code to
(From x In m.Listen(Of Maybe(Of NominalObject))()
From y In x
Select New LAPViewCommands(y)).
BindToControl(Me, Function(x) x.ViewModel).
DisposeWith(Me)
I have a compile error. Note there is no problem with the fluent syntax.
m.
Listen(Of Maybe(Of NominalObject)).
SelectMany(Function(x) x.Select(Function(y) New LAPViewCommands(y))).
BindToControl(Me, Function(x) x.ViewModel).
DisposeWith(Me)
Is this problem a strange edge case of the VB.NET parser or is there something
important here I'm missing? In summary the question is. Why can't I bracket a
LINQ query expression and then use fluent extension methods that return void
The problem is that your expression doesn't start with an identifier.
It's a limitation of VB.Net and not limited to LINQ query expressions.
Compare the following C# code (Dump is an extension method)
"123".Dump();
(from a in "1223" select a).Dump();
new object().ToString();
which will work fine. Here's the VB.Net equivalent (which more or less looks the same):
"123".Dump()
(From a in "123" Select a).Dump()
(New Object()).ToString()
and each of the three statements will throw a syntax error.
You can fix it by using the Call statement:
Call "123".Dump()
Call (From a in "123" Select a).Dump()
Call New Object().ToString()

late binding in linq

I have a simple LINQ query that is going against a collection.
Dim oList = From w In Os
Order By w.ClassTitle Descending
Select w
What I'd like to be able to do though is pass into this whether it's descending or ascending. I'm not sure how to do that.
Also, if I were to have a where clause in here.. say
where w.ClassTitle = "Test"
How can I make the "Test so that I can pass it into the LINQ query.
Thanks
shannon
I dont think you can pass that "into" this query, however you could do the regular query
var oList = from w in Os
select w
Then when the user takes some action you could simply do an order by after that fact.
oList.OrderBy(o => o.ClassTitle)
or
oList.OrderByDescending(o => o.ClassTitle)
UPDATE:
As far as the late binding, what you could do is write a method that would execute the Where clause. Perhaps using an extension method might work. I'm more familiar with C# so my syntax might be a bit off
public static IEnumerable<Os> ExecuteWhere (this Table<Os> table, Expression<Func<Os, bool>> predicate)
{
return table.AsQueryable<Os>().Where(predicate);
}
Then to call it like so:
oList.ExecuteWhere(a => a.ClassTitle == "Test")
Use delegation syntax. For example;
Dim oList = Os.Where(....).OrderBy(...)...

VB.net can't find by string

Using VB.net, the following snippet gives the error below.
Dim _account = Account.Find(Function(x As Account) x.AccountName = txtFilterAccountName.Text)
or similarly if I do
.SingleOrDefault (Function(x As Account) x.AccountName = txtFilterAccountName.Text)
will both give the error "The method 'CompareString' is not supported". If I make the same call searching for an integer (ID field) it works fine.
.SingleOrDefault (Function(x As Account) x.Id = 12)
So integer matching is fine but strings don't work Is this a problem with the VB.net templates?
No this is not a problem with Vb.Net templates.
The problem is that you are not using a normal LINQ provider. Based on your tag (subsonic) I'm guessing you're using a LINQ to SQL query.
The problem is that under the hood, this is trying to turn your code into an expression tree which is then translated into an SQL like query. Your project settings are turning your string comparison into a call in the VB runtime. Specifically, Microsoft.VisualBasic.CompilerServices.Operators.CompareString.
The LINQ2SQL generater in question or VB compiler (can't remember where this check is done off the top of my head) does not understand how to translate this to an equivalent bit of SQL. Hence it generates an error. You need to use a string comparison function which is supported by LINQ2SQL.
EDIT Update
It looks like the CompareString operator should be supported in the Linq2SQL case. Does subsonic have a different provider which does not support this translation?
http://msdn.microsoft.com/en-us/library/bb399342.aspx
The problem is with SubSonic3's SQL generator and the expression tree generated from VB.NET.
VB.NET generates a different expression tree as noted by JaredPar and SubSonic3 doesn't account for it - see Issue 66.
I have implemented the fix as described but it has yet to merge into the main branch of SubSonic3.
BlackMael's fix has been committed:
http://github.com/subsonic/SubSonic-3.0/commit/d25c8a730a9971656e6d3c3d17ce9ca393655f50
The fix solved my issue which was similar to John Granade's above.
Thanks to all involved.