LLBLGen Pro: How to evaluate an EntityField for a given String - vb.net

I have an LLBLGen Pro project which has generated VB.Net 2.0 Self Servicing code.
I have a function to return a list of custom structures based on a search using the generated code.
I would like to supply a Dictionary of FieldNames and Values to this function and for each one add a new Predicate Expression to the search.
How can I check the String within the dictionary that represents the Field name and work out which EntityField to add the Predciate Expression for?
Code Sample
Dim dbFiles As New AllFilesCollection
Dim dbFilter As New PredicateExpression
If Not String.IsNullOrEmpty(ClientName) Then
dbFilter.Add(New PredicateExpression(AllFilesFields.ClientMenuName = ClientName))
End If
If Not String.IsNullOrEmpty(SearchText) Then
dbFilter.Add(New FieldLikePredicate(AllFilesFields.ClientReference, "%" & SearchText & "%"))
dbFilter.AddWithOr(New FieldLikePredicate(AllFilesFields.Cmsnumber, "%" & SearchText & "%"))
End If
For Each Filter As KeyValuePair(Of String, String) In Filters
'Custom code here to determine the field to add a filter for.
Next
dbFiles.GetMulti(dbFilter)

I think that this question has been ignored because it looks like an LLBLGEN question, but it probably isn't.
If you know all of your Columns:
City
State
Zip
Then you just need to convert your string to those values like this...
For Each Filter As KeyValuePair(Of String, String) In Filters
Select Case filter.Key
Case "City"
dbFilter.Add(New PredicateExpression(AllFilesFields.City = filter.Value))
Case "State"
dbFilter.Add(New PredicateExpression(AllFilesFields.State = filter.Value))
Case "Zip"
dbFilter.Add(New PredicateExpression(AllFilesFields.Zip = filter.Value))
End Select
Next

You also could do something like this:
Dim fields As IEntityFields = new AllFieldsEntityFactory().CreateFields();
For Each Filter As KeyValuePair(Of String, String) In Filters
dbFilter.Add((EntityField) fields[Filter.Key] == Filter.Value);
Next

Related

Convert an unknown structure to an untyped Object in VB.NET

I'd like to convert an unknown basic structure to an Object (no type here).
I'm building a library that will be used by many users to extract data from my system but don't want to do a new function for everyone of them. They have to know what will be the result.
In vb, it is possible to create an Object with some properties and use it as it is a regular Class like so:
Dim myObj as New With { .name = "Matt", .age = "28" }
MsgBox( myObj.name & " is now " & myObj.age & " years old.")
So far, so good.
Next step : my user will give me some instructions that I need to extract data from various DBs, and I've no idea of what the result will be.
What I know after the execution is a list of String containing the columns of the result set and, of course a (set of) rows.
And here is the problem of course
My function (for a single row) so far:
Public Function GetData(ByVal instructions as String) as Object ' User is supposed to know what will be inside, instructions is as XML describing DB, table, query, ...
' Do what is needed to retrieve data
' Here I have a variable cols As List(Of String) ' e.g. ("BP", "NAME", "VAT")
Dim o As New With ???
Return o
End Function
What I've tried: build a fake JSon on the fly, and try to Deserialize to Object.
But even if it seems to work, I (and the user) can't access the property as in my top piece of code like:
MsgBox(o.BP)
I know that I could do
Public Function GetData(Of T As {New})(ByVal instructions as String) As T
Dim o As T
' Use some Reflexion to TryInvokeMember of T
Return o
End Function
But I wanted to remove the hassle to create a class to use my code.
Plus, My librairy will be use in a webservice and the class of the user is then unknown.
One approach could be - to use Dictionary(Of String, Object)
Public Function GetData(instructions as String) As Dictionary(Of String, Object)
Dim data = ' Load data
Dim columns As String() = { "BP", "NAME", "VAT" }
Return columns.ToDictionary(
Function(column) column,
Function(column) data.GetByColumnName(column)
)
End Function
` Usage
Dim result = GetDate("instructions: ['BP', 'NAME']")
' Because user knows it is Integer
Dim bpValue = DirectCast(result.Item("BP"), Integer)
Thanks to #GSerg, #Fabio and a few other searches about ExpandoObject, I did it !
Imports System.Dynamic
Dim o As Object = New ExpandoObject()
For Each col In cols
DirectCast(o, IDictionary(Of String, Object)).Add(col, row.GetString(col))
Next

extract list of string from list of custom class

i have a list(of custom class)
and i want to extract a list of all 'name' String, from it, through linq
I know how to do with a loop, but i need to get it with a linear, brief linq instruction.
i've checked this help
C# Extract list of fields from list of class
but i have problem in linq correct syntax
in particular because i would like to extract a New List(Of String)
Class Student
Sub New(ByVal NewName As String, ByVal NewAge As Integer)
Name = NewName
Age = NewAge
End Sub
Public Name As String
Public Age As Integer
End Class
Public Sub Main
Dim ClassRoom as New List(Of Student) From {New Student("Foo",33), New Student("Foo2",33), New Student("Foo3",22)}
Dim OneStudent as Student = ClassRoom(0)
Dim AllStudentsNames As New List(Of String) From {ClassRoom.Select(Function(x) x.Name <> OneStudent.Name).ToList}
End Sub
But something wrong...
Any help?
P.S. Since c# it's close to vb.Net, also c# helps are well welcome.
First, you don't need to create a new list From the one returned by the LINQ method. It's already in a new list at that point, so you can just set AllStudentsNames equal directly to what the ToList method returns.
Second, you are not selecting the name. You are selecting the result of the equality test to see if the names are different. In other words, when you say Select(Function(x) x.Name <> OneStudent.Name), that returns a list of booleans, where they true if the names are different and false if the names are the same. That's not what you want. You want the list of names, so you need to select the name.
Third, if you need to filter the list so that it only returns ones where the name is different, then you need to add a call to the Where method.
Dim AllStudentsNames As List(Of String) = ClassRoom.
Where(Function(x) x.Name <> OneStudent.Name).
Select(Function(x) x.Name).
ToList()

LINQ Returning string array from DB.ExecuteQuery

I am simply trying to return a list of strings (just one field in a table) using the LINQ function Db.Executequery, but the following does not compile
Dim names = datacontext1.ExecuteQuery(of String()) _
("Select customerName from customers",nothing)
It looks like I cannot simply return a list of strings, it has to be a user defined class. (I tried just String, List(of String),etc but no luck.) This is kind of cumbersome, because I cannot be declaring a class for each and every string field. (BTW, this will be a dynamic query, that is why I am not using the ORM mapping features)
The following does compile:
dim customerList = datacontext1.ExecuteQuery(of Customer) _
("Select * from customers",nothing)
The following should run just fine (assuming northwind database):
Dim names = datacontext1.ExecuteQuery(of String()) _
("SELECT contactname FROM customers")

How To Use LINQ To Find Matching Data Against A List Of Strings

I have a specialized string dictionary of (string, string) (_RulesAndTheirDescriptions) that contains the name (key) and description (value) of methods in a given class. I currently do the following query to search for a match on the key or value and then bind that to a grid. Works great!
Dim Results = From v In _RulesAndTheirDescriptions _
Where v.Value.ToString().ToUpper().Contains(Me.txtSearchFor.Text.ToUpper()) _
Or v.Key.ToString().ToUpper().Contains(Me.txtSearchFor.Text.ToUpper()) _
Order By v.Key _
Select New With {.Rule = v.Key, .Description = v.Value.ToString()}
This works great when matching "word" or perhaps even "my word" but I would like to search for "my" and "word" and "also this". Meaning words and phrases seperated by spaces. Much like google and bing. When the user enters a value I only would require that the phrases be quoted. The following RegEx takes care of getting me a list word/phrase the user is looking for. Now I am having a hard time combining the the above query that works with the new enhanced list.
Please excuse the below code. I am just trying to test things and get it working.
Dim b As Match
b = Regex.Match(Me.txtSearchFor.Text, "(?<=(?:^|\s|,)"")[^""]*?(?="")|(?<=\s|^)(?!"")[\w\W]+?(?=\s|$)")
Dim sl As List(Of String) = New List(Of String)
If b.Success Then
sl.Add(b.Value.ToUpper())
Dim sMatch = b.NextMatch()
While sMatch IsNot Nothing AndAlso sMatch.Success
sl.Add(sMatch.Value.ToUpper())
sMatch = sMatch.NextMatch()
End While
End If
Per another post on this site I tried to do the following but that is not returing any results. I suspect because the sl.ToString() returns the type and not the value?
Dim Results = From v In _RulesAndTheirDescriptions _
Where v.Value.ToString().ToUpper().Contains(sl.ToString()) _
Order By v.Key _
Select New With {.Rule = v.Key, .Description = v.Value.ToString()}
If I am going about this all wrong, please enlighten me. Seems like it should be easy.
Thanks in advance,
Kevin
Hello You have to have a cross join to solve this problem
Dim Results = From v In _RulesAndTheirDescriptions _
join y in sl on 1 equals 1
Where v.Value.ToString().ToUpper().Contains(y) _
Order By v.Key _
Select New With {.Rule = v.Key, .Description = v.Value.ToString()}
This can produce duplicates when more than one token can match a rule.So you can do a distinct if you want unique values
Like Results.Distinct()

How do I append a 'where' clause using VB.NET and LINQ?

I am pretty new to VB.NET and am having a bit of trouble here with something I thought should be simple.
Keeping it simple, let's say I have a Document table with "Name" that I want to search on (in reality there are several other tables, joins, etc. ..). I need to be able to build the query using a where clause based on string values passed in.
Example - the user may pass in "ABC", "ABC DEF", "ABC DEF GHI".
The final query would be (the syntax is not correct, I know):
Select * from Documents Where Name Like %ABC% AND Name Like %DEF% AND Name like %GHI%
So, I thought I could do something like this.
Dim query = From document In _context.Documents
<< loop based on number of strings passed in >>
query = query.Where( ... what goes here?? )
For some reason, being brain-dead or something, I can't figure out how to make this work in VB.NET, or if I'm doing it correctly.
I believe this is how you would do it in VB (I'm a C# developer):
query = query.Where(Function(s) s = "ABC")
See LINQ - Sample Queries for some examples.
I think the tricky part here is the unknown number of query parameters. You can use the underlying LINQ IQueryable(Of T) here to help.
I think the following would work (it's not compiled, just notepad code here):
Public Function GetDocuments(criteria as String)
Dim splitCriteria = SplitTheCriteria(criteria)
dim query = from document in _context.Documents
For Each item in splitCriteria
Dim localItem = item
query = AddCriteriaToQuery(query, localItem)
Next
dim matchingDocuments = query.ToList()
End Function
Private Function AddCriteriaToQuery(query as IQueryable(Of Document), criteria as string) as IQueryable(Of Document)
return query.Where(Function(doc) doc.Name = criteria)
End Function
Since LINQ will delay-execute the query you can append where clauses onto your query in the loop and then call .ToList() at the end to execute the query.
In LINQ to SQL you can add WHERE clauses to your query using the .Where method of the query object, as you noted in your question. To use the LIKE operator, try using the .Contains method of the object you're querying in the Lambda expression of your call to the Where method.
Here's a simplified example in a console application. Hopefully it will lead you in the correct direction.
Public Class Doc
Private _docName As String
Public Property DocName() As String
Get
Return _docName
End Get
Set(ByVal value As String)
_docName = value
End Set
End Property
Public Sub New(ByVal newDocName As String)
_docName = newDocName
End Sub
End Class
Sub Main()
Dim Documents As New List(Of Doc)
Documents.Add(New Doc("ABC"))
Documents.Add(New Doc("DEF"))
Documents.Add(New Doc("GHI"))
Documents.Add(New Doc("ABC DEF"))
Documents.Add(New Doc("DEF GHI"))
Documents.Add(New Doc("GHI LMN"))
Dim qry = From docs In Documents
qry = qry.Where(Function(d) d.DocName.Contains("GHI"))
Dim qryResults As List(Of Doc) = qry.ToList()
For Each d As Doc In qryResults
Console.WriteLine(d.DocName)
Next
End Sub
Note the .Contains("GHI") call in the Lambda expression of the .Where method. I'm referencing the parameter of the expression, "d", which exposes the DocName property, which further exposes the .Contains method. This should produce the LIKE query you're expecting.
This method is additive, i.e. the call to the .Where method could be enclosed in a loop to make additional LIKE operators added to the WHERE clause of your query.
Dim query = From document In _context.Documents where document.name = 'xpto' select document
Or
Dim query = From document In _context.Documents where document.name.contains('xpto') select document
If you do this in a loop, you can do something like this:
.Where(Function(i as mytype) i.myfiltervar = WhatIWantToSelect)