Linq join typeddatatable with List and return typeddatatable - vb.net

I hava a strongly typed datatable and a list(of String).
I want to build a linq query to return a datatable of the same type where the fields of a certain column of the table are in the list. I thought of doing a Join, although in normal sql I would have added
SELECT FROM Table WHERE Table.ID IN(...);
This is what I tried in linq.
Dim Families As List(Of String)
Dim Articles As SomeStronglyTypedDataTable
Dim MatchingArticles = From a In Articles.AsEnumerable _
Join f In Families.AsEnumerable On a.FamilyCode Equals f.ToString _
Select New With {}
I'm not sure either if I need to convert the query result back to a datatable nor if that's even possible.
Thanks!

Try the simpler query:
Dim MatchingArticles = From a In Articles.AsEnumerable _
Where Families.Contains(a.FamilyCode)_
Select a
Dim MyMatchingArticlesTable = CopyToDataTable(Of SomeStronglyTypedDataTable) (MatchingArticles)

Yes, you can do this. Instead of Select New ..., select the matching DataRows, Select a, and then use CopyToDataTable(Of T) on the matching rows.

Dim table As DataTable = query.CopyToDataTable()
Dim typedtable As New TypedDataset.TypedDataTable
typedtable.Merge(table)

I was raking my brain trying to get something similar to work, and your code enlightened me.
All I needed was to add the .AsEnumerable() on both sides.
I'm working with C#. Anyway, I think all you need to do is select your table like
Dim MatchingArticles = From a In Articles.AsEnumerable _
Join f In Families.AsEnumerable On a.FamilyCode Equals f.ToString _
Select a;
Well, this is a very old post, but hey, it might help someone else...
If you think this would resolve your question, please mark it as correct, so others will know. You may also want to mark Devart's answer as correct. I tried it and it works.

Related

How NOT filter LINQ results if criteria list is empty?

When filter criteria is passed to my LINQ query, no problem:
Dim statesSelected As String = {‘GA’,’FL’}
Dim results As IEnumerable(Of Person) = _
From p As Person in dc.Persons _
Where statesSelected.Contains(p.StateCode)
HOWEVER, if no filter criteria are selected, then I want ALL states returned (instead of none which is what the above would do). How can I do this, please? I realize I could have an IF statement around the query, but in reality I’ll have many filters (and will want to handle them all within the one query).
Thanks for any help.
I am not sure if this would translate to SQL, but you can try this approach:
Dim results As IEnumerable(Of Person) = _
From p As Person in dc.Persons _
Where statesSelected Is Nothing OrElse statesSelected.Contains(p.StateCode)
In this case if your variable statesSelected is nothing then only the first part of query would be executed, otherwise first part would be true and only second condition would matter
Try this out:
Dim results As IEnumerable(Of Person) = _
From p As Person In Persons
Where If(statesSelected.Length < 1, p.StateCode <> "", statesSelected.Contains(p.StateCode))
What it's doing is checking to make sure statesSelected has elements. If not, it simply brings back all elements. If there values in statesSelected, it brings back the ones that contain that state.
The magic is happening in the ternary If() : https://msdn.microsoft.com/en-us/library/bb513985.aspx?f=255&MSPPError=-2147217396

LINQ - left join to find unmatched records

I'm trying to execute a left join between 2 datatables that will return all records from the left table without a corresponding value in the right table on the join criteria. As of now I have the following which returns nothing:
Dim Query1 = From exasset In dtExistingAssets _
GroupJoin asset In dtNewAssets _
On exasset("ACCOUNT_NAME") Equals asset("ACCOUNT_NAME") _
Into results = Group _
From f In results.DefaultIfEmpty _
Where IsDBNull(f) _
SelectNewWith _
{ //...
I've seen several references to using Any but I wasn't able get the syntax correct. Can anyone please help out? This is something that is really simple to accomplish in SQL but seems a lot more complicated in LINQ.
I think the problem is the IsDBNull(f), a left join will result in a null value (Nothing in VB) not a DBNull value. I think you should change it to: ``
...
From f In results.DefaultIfEmpty _
Where f is Nothing
I would use the strongly typed DataRow extension methods like Field which also support nullables.
Dim query = From exAsset In dtExistingAssets
Group Join newAsset In dtNewAssets
On exAsset.Field(Of String)("ACCOUNT_NAME") Equals newAsset.Field(Of String)("ACCOUNT_NAME") Into Group
From joinedAssets In Group.DefaultIfEmpty()
Where joinedAssets.Field(Of String)("ACCOUNT_NAME") Is Nothing
If you just want to know the new accounts, you can also use the efficient Enumerable.Except:
Dim existingAccounts = From exRow In dtExistingAssets
Select exRow.Field(Of String)("ACCOUNT_NAME")
Dim newAccounts = From newRow In dtNewAssets
Select newRow.Field(Of String)("ACCOUNT_NAME")
Dim newAccNotInExisting = newAccounts.Except( existingAccounts )

Convert a two-table exists query from SQL to Linq using dynamic fields in the subquery

I'm trying to query old Access database tables and compare them with SQL Server tables.
They often don't have primary keys, or they have extra fields that had some purpose in the nineties, etc., or the new tables have new fields, etc.
I need to find records - based on a set of fields specified at runtime - that are in one table but not another.
So, I do this kind of query all the time in SQL, when I'm comparing data in different tables:
dim fields_i_care_about as string = "field1, field2, field3"
'This kind of thing gets set by a caller, can be any number of fields, depends on the
'table
dim s as string= ""
dim flds = fields_i_care_about.split(",")
for i as integer = 0 to ubound(flds)
if s > "" then s += " AND "
s += " dysfunctional_database_table." & flds(i) & "=current_database_table." & flds(i)
next
s = "SELECT * from dysfunctional_database_table where not exists (SELECT * from current_database_table WHERE " & s & ")"
====
I'm trying to do this using Linq because it seems like some of the datatype problems with two different database types become less of a headache,
but I'm new to Linq and totally stuck.
I got as far as this:
Put old and new tables into datatables as dt1 and dt2
Dim new_records = _
From new_recs In dt2.AsEnumerable
Where Not ( _
From old_recs In dt1.AsEnumerable Where old_recs(field1) = new_recs(field1) AndAlso old_recs(field2) = new_recs(field2)).Any
Select new_recs
But I can't figure out how to put this part in on the fly -
old_recs(field1) = new_recs(field1) AndAlso old_recs(field2) = new_recs(field2)
So far I've tried:
putting the fields I want to compare and making them a string and just putting that string in as a variable ( I thought I was probably cheating, and I guess I was)
dim str = old_recs(field1) = new_recs(field1) AndAlso old_recs(field2) = new_recs(field2)
From new_recs In dt2.AsEnumerable
Where Not ( _
From old_recs In dt1.AsEnumerable Where str).Any
Select new_recs
It tells me it can't convert a Boolean -
Is there any way to do this without Linq expressions? They seem far more complex than what I'm trying to do here, and they take a lot of code, and also I can't seem to find examples of Expressions where we're comparing two fields in a subquery.
Is there a simpler way? I know I could do the usual EXISTS query using JOIN or IN - in this case I don't need the query to be super fast or anything. And I don't need to use a DataTable or DataSet - I can put the data in some other kind of object.
So I found a lot of sample code that used MethodInfo and reflection and things like that, but I couldn't get any of it to work - these Datarows have a Field method but it requires that you add an (of object) argument before the field name argument and that's tricky to do.
So I'm not sure if this solution is the most efficient way, but at least it works. I'd be interested in finding out whether this way of doing it is efficient and why or why not. It seemed like most people used reflection to do this kind of thing, but I couldn't get that working properly and anyway what I'm trying to do is pretty simple while those methods were pretty complex. I suppose I'm doing Linq with a SQL mindset, but anyway it works.
Dim f As Func(Of DataRow, DataRow, String, Boolean) = Function(d1 As DataRow, d2 As DataRow, s As String)
Dim fields = Split(s, ",")
Dim results As Boolean = True
For k As Integer = 0 To UBound(fields)
Dim obj = DataRowExtensions.Field(Of Object)(d1, fields(k))
Dim obj2 = DataRowExtensions.Field(Of Object)(d2, fields(k))
If obj <> obj2 Then results = False : Exit For
Next
Return results
End Function
Dim new_records = _
From new_recs In dt2.AsEnumerable.AsQueryable()
Where Not ( _
From old_recs In dt1.AsEnumerable.AsQueryable Where f(old_recs, new_recs, id_key)).Any
Select new_recs
Try
Return new_records.CopyToDataTable
Catch ex As Exception
Stop
End Try

Sorting numbers in descending order

I have 20 textboxes. each contains a particular number . I want the textbox1 to textboxN to have the numbers in the descending order. If any of the textbox has a zero value then I want to leave that textbox as it is. A sample code in vb.net needed.
'for sorting the elements in descending order
dim array(4) as integer
array(4)={4,6,2,9,1}
'first sort the array and then reverse it as
array.sort(4)
array.reverse(4)
sortlistbox.item.add(array(4))
Dim txt As New List(Of TextBox)
Dim q = From i In txt
Where CInt(i.Attributes("value")) > 0
Order By CInt(i.Attributes("value")) Descending
Select i
Whana try some simple linq query over your collection?
This one is a bit old, but I ran into the same problem.
Using MSDN I found this: Enumerable.OrderBy Method (IEnumerable, Func)
If you just add .Reverse to that query, it's descending:
Dim query As IEnumerable(Of Pet) = pets.OrderBy(Function(pet) pet.Age).Reverse
#Thom Morgan
This one is a bit old, but I ran into the same problem.
Using MSDN I found this: Enumerable.OrderBy Method (IEnumerable, Func)
If you just add .Reverse to that query, it's descending:
Dim query As IEnumerable(Of Pet) = pets.OrderBy(Function(pet) pet.Age).Reverse
This worked like a charm! Thank you!

LINQ / VB.NET select distinct from dataset

I have a single columned datatable inside a single tabled dataset.
I just want to convert this dataset to distinct rows. Here is my code, it gives compile error '.' expected. What am I doing wrong? (I tried adding the ., still same error). I know this is something stupidly obvious. PLZ Save me! ;)
Thanks much in advance!
Dim query = _
From email In ds.Tables(0) _
Select email.Field<string>("Email").Distinct()
EDIT: DOH! MIXING VB/C# SYNTAX HERE! I changed to (Of String) and it works... BUT NOW 'query' is an ienumerable collection of characters... not a datatable... so how do I convert back easily without manually doing a loop?? Plz advise!
You are applying the Distinct method to each string, not the result of the query. As strings are collection of character, you can apply extension methods to them too.
Put parentheses around the query:
Dim query = _
(From email In ds.Tables(0) _
Select email.Field(Of String)("Email")).Distinct()
You can use the distinct values after getting the values into datatabale by:
dtFiltered = dtNotFiltered.DefaultView.ToTable(True, "RAMI_ISSA") 'Get distinct values (by stting the first parameter to True)