VB.NET LINQ to DataSet (SQL 'LEFT OUTER JOIN' alternative) - vb.net

I would like to join two DataTables and create the third one from the result. The result DataTable should have three columns:
ID
Name
YearOfBirth
My Compile options:
Option explicit: On
Option strict: On
Option compare: Binary
Option infer: Off
Dim dr As DataRow
REM Dt1
Dim Dt1 As New DataTable
Dt1.Columns.Add("ID", GetType(Integer))
Dt1.Columns.Add("Name", GetType(String))
dr = Dt1.NewRow
dr("ID") = 1
dr("Name") = "Peter"
Dt1.Rows.Add(dr)
dr = Dt1.NewRow
dr("ID") = 2
dr("Name") = "Anna"
Dt1.Rows.Add(dr)
dr = Dt1.NewRow
dr("ID") = 3
dr("Name") = "John"
Dt1.Rows.Add(dr)
REM End Dt1
REM Dt2
Dim Dt2 As New DataTable
Dt2.Columns.Add("ID", GetType(Integer))
Dt2.Columns.Add("YearOfBirth", GetType(Integer))
dr = Dt2.NewRow
dr("ID") = 1
dr("YearOfBirth") = 1970
Dt2.Rows.Add(dr)
dr = Dt2.NewRow
dr("ID") = 2
dr("YearOfBirth") = 1980
Dt2.Rows.Add(dr)
REM End Dt2
Dim Dt3 As New DataTable
Dim query As IEnumerable(Of DataRow) = From dr1 In Dt1.AsEnumerable()
Group Join dr2 In Dt2.AsEnumerable()
On dr1.Field(Of Integer)("ID") Equals dr2.Field(Of Integer)("ID")
Into joined = Group
From j In joined.DefaultIfEmpty()
Select New With
{
.ID = dr1.Field(Of Integer)("ID"),
.Name = dr1.Field(Of String)("Name"),
.YearOfBirth = j.Field(Of Integer)("YearOfBirth")
}
Dt3 = query.CopyToDataTable
But I get the error message in editor (VS 2017):
"Error BC36754:
'IEnumerable(Of anonymous type: ID As Integer, Name As String, YearOfBirth As Integer)' cannot be converted to 'IEnumerable(Of DataRow)' because 'anonymous type: ID As Integer, Name As String, YearOfBirth As Integer' is not derived from 'DataRow', as required for the 'Out' generic parameter 'T' in 'Interface IEnumerable(Of Out T)'."

Select New without specifying class name as query result will return anonymous type (such like IEnumerable(Of AnonymousType)), and CopyToDataTable() throwing exception because IEnumerable(Of AnonymousType) cannot be converted directly to IEnumerable(Of DataRow).
Hence, you need to convert anonymous type into DataRow using additional Select method that iterates IEnumerable(Of AnonymousType) contents and returns DataRow with DataTable.NewRow() (using prepared DataTable which includes column names as result set):
' joined DataTable columns
Dim JoinedDT As New DataTable
JoinedDT.Columns.Add("ID", GetType(Integer))
JoinedDT.Columns.Add("Name", GetType(String))
JoinedDT.Columns.Add("YearOfBirth", GetType(Integer))
' other stuff
Dim query As IEnumerable(Of DataRow) = (From dr1 In Dt1.AsEnumerable() _
Group Join dr2 In Dt2.AsEnumerable() _
On dr1.Field(Of Integer)("ID") Equals dr2.Field(Of Integer)("ID") _
Into joined = Group _
From j In joined.DefaultIfEmpty() _
Select New With
{
.ID = dr1.Field(Of Integer)("ID"),
.Name = dr1.Field(Of String)("Name"),
.YearOfBirth = If(j IsNot Nothing, j.Field(Of Integer)("YearOfBirth"), 0)
}).Select(Function(r)
' use `DataTable.NewRow` here
Dim row As DataRow = JoinedDT.NewRow()
row("ID") = r.ID
row("Name") = r.Name
row("YearOfBirth") = r.YearOfBirth
Return row
End Function)
Dt3 = query.CopyToDataTable()
Reference:
Get linq to return IEnumerable<DataRow> result (C# version)

Related

Merge two DataTables using an Inner Join in vb.net

I have two DataTables that need to be merged together. Both Tables have a field in it called "Code" Basically if one table has a certain code, it merges with the corresponding code in the other table, getting that rows values merged into it. I would say its like merging two tables together in SQL using an inner join.
Needs to be in vb.net please!
Here is a VB conversion of this answer.
Dim dt1 As New DataTable()
dt1.Columns.Add("CustID", GetType(Integer))
dt1.Columns.Add("ColX", GetType(Integer))
dt1.Columns.Add("ColY", GetType(Integer))
Dim dt2 As New DataTable()
dt2.Columns.Add("CustID", GetType(Integer))
dt2.Columns.Add("ColZ", GetType(Integer))
For i As Integer = 1 To 5
Dim row As DataRow = dt1.NewRow()
row("CustID") = i
row("ColX") = 10 + i
row("ColY") = 20 + i
dt1.Rows.Add(row)
row = dt2.NewRow()
row("CustID") = i
row("ColZ") = 30 + i
dt2.Rows.Add(row)
Next
Dim results = From table1 In dt1.AsEnumerable()Join table2 In dt2.AsEnumerable() On CInt(table1("CustID")) = CInt(table2("CustID"))New With { _
Key .CustID = CInt(table1("CustID")), _
Key .ColX = CInt(table1("ColX")), _
Key .ColY = CInt(table1("ColY")), _
Key .ColZ = CInt(table2("ColZ")) _
}
For Each item As var In results
Console.WriteLine([String].Format("ID = {0}, ColX = {1}, ColY = {2}, ColZ = {3}", item.CustID, item.ColX, item.ColY, item.ColZ))
Next
Console.ReadLine()

How to convert 2 dimensional arraylist to datatable?

I need a function that returns a datatable, from any arraylist (2 dimensions) as arguments? Thanks for your help
Creating two dimensional Arraylist:
Public Overrides Function Find(Optional ByRef conditions As ArrayList = Nothing) As System.Collections.ArrayList
Dim collection As New ArrayList
Dim cmd ......... ' Select command based on an arraylist of conditions
Dim dr As SqlDataReader = cmd.ExecuteReader()
While dr.Read()
Dim cnt As New contact
cnt .Id() = dr("id")
cnt .Name= dr("name")
'......... other columns are imported
collection.Add(cnt )
End While
dr.Close()
Return collection
End Function
Suitable solution found:
Public Shared Function ArrayListToDataTable(ByVal arraylist1 As ArrayList) As System.Data.DataTable
Dim dt As New System.Data.DataTable()
For i As Integer = 0 To arraylist1.Count - 1
Dim GenericObject As Object = arraylist1.Item(i)
Dim NbrProp As Integer = GenericObject.GetType().GetProperties().Count
For Each item As PropertyInfo In GenericObject.GetType().GetProperties()
Try
Dim column = New DataColumn()
Dim ColName As String = item.Name.ToString
column.ColumnName = ColName
dt.Columns.Add(column)
Catch
End Try
Next
Dim row As DataRow = dt.NewRow()
Dim j As Integer = 0
For Each item As PropertyInfo In GenericObject.GetType().GetProperties()
row(j) = item.GetValue(GenericObject, Nothing)
j += 1
Next
dt.Rows.Add(row)
Next
Return dt
End Function
After 2 years, Let me answer this=>
Function ConvertArrayListToDataTable(ByVal arraylist As ArrayList) As DataTable
Dim dt As DataTable = New DataTable()
If arraylist.Count <= 0 Then
Return dt
End If
Dim propertiesinfo As PropertyInfo() = arraylist(0).GetType().GetProperties()
For Each pf As PropertyInfo In propertiesinfo
Dim dc As DataColumn = New DataColumn(pf.Name)
dc.DataType = pf.PropertyType
dt.Columns.Add(dc)
Next
For Each ar As Object In arraylist
Dim dr As DataRow = dt.NewRow
Dim pf As PropertyInfo() = ar.GetType().GetProperties()
For Each prop As PropertyInfo In pf
dr(prop.Name) = prop.GetValue(ar, Nothing)
Next
dt.Rows.Add(dr)
Next
Return dt
End Function

return Datatable from linq query

I am trying to return data table from linq query but getting error message. I am using .net framework 4.0 in VS2012.
<Table>
Public Class StaffOfficeAccess
<Column(CanBeNull:=False, IsPrimaryKey:=True, IsDbGenerated:=True)>
Public Property StaffOfficeAccessID As Int32 = 0
<Column>
Public Property StaffID As Int32 = 0
<Column>
Public Property OfficeID As Int32 = 0
<Column(IsVersion:=True, IsDbGenerated:=True)>
Public Property Version As Byte()
End Class
'----------------------------'
Public Function GetByStaffID(ByVal staffID As Int32) As DataTable
Dim query As IEnumerable(Of DataRow) = CType((From oa In db.StaffOfficeAccess.AsEnumerable() _
Join o In db.Office.AsEnumerable() On oa.OfficeID Equals o.OfficeID _
Select oa.OfficeID,
o.OfficeName), Global.System.Collections.Generic.IEnumerable(Of Global.System.Data.DataRow))
Dim table As DataTable = System.Data.DataTableExtensions.CopyToDataTable(query)
Return table
End Function
'-------error----------'
Unable to cast object of type 'd__614[staff.Objects.StaffOfficeAccess,AMIS.Objects.Office,System.Int32,VB$AnonymousType_02[System.Int32,System.String]]' to type 'System.Collections.Generic.IEnumerable`1[System.Data.DataRow]'.
I have tried the example here https://msdn.microsoft.com/en-us/library/bb396189%28v=vs.110%29.aspx but no luck. I don't get CopyToDataTable in VS2012.
Just another approach by using Aggregate extension method MSDN
Dim dt As New DataTable()
dt.Columns.Add("OfficeID", GetType(Integer))
dt.Columns.Add("OfficeName", GetType(String))
Dim query = From oa In db.StaffOfficeAccess.AsEnumerable()
Join o In db.Office.AsEnumerable()
On oa.OfficeID Equals o.OfficeID
Select oa.OfficeID, o.OfficeName
query.Aggregate(Of DataTable)(dt,
Function(dtb, o)
Dim dr As DataRow = dtb.NewRow()
dr.SetField("OfficeID", o.OfficeID)
dr.SetField("OfficeName", o.OfficeName)
dtb.Rows.Add(dr)
Return dtb
End Function)
I have tried this and it works.
Dim dt As New DataTable()
dt.Columns.Add("OfficeID", GetType(Integer))
dt.Columns.Add("OfficeName", GetType(String))
Dim query = From oa In db.StaffOfficeAccess.AsEnumerable() _
Join o In db.Office.AsEnumerable() On oa.OfficeID Equals o.OfficeID _
Select oa.OfficeID,
o.OfficeName
For Each item In query
Dim dr As DataRow = dt.NewRow()
dr("OfficeID") = item.OfficeID
dr("OfficeName") = item.OfficeName
dt.Rows.Add(dr)
Next

Converted C# To VB.NET , But Vb.net code Not working ,Below converted code is pasted .i got the error Linq part

Dim dt As New DataTable("MyTable")
dt.Columns.Add(New DataColumn("Name"))
dt.Columns.Add(New DataColumn("Place"))
dt.Columns.Add(New DataColumn("date", Type.[GetType]("System.String")))
create the data table
Dim dr As DataRow = dt.NewRow()
dr("Name") = "500"
dr("Place") = "Chennai"
dr("date") = "10-May-2014"
dt.Rows.Add(dr)
Dim dr1 As DataRow = dt.NewRow()
dr1("Name") = "600"
dr1("Place") = "Chennai"
dr1("date") = "11-May-2014"
dt.Rows.Add(dr1)
added the row
Dim dr2 As DataRow = dt.NewRow()
dr2("Name") = "200"
dr2("Place") = "Bangalore"
dr2("date") = "12-Aug-2014"
dt.Rows.Add(dr2)
Dim dr3 As DataRow = dt.NewRow()
dr3("Name") = "40"
dr3("Place") = "Chennai"
dr3("date") = "14-May-2014"
dt.Rows.Add(dr3)
Dim dr5 As DataRow = dt.NewRow()
dr5("Name") = "9000"
dr5("Place") = "Bangalore"
dr5("date") = "15-Aug-2014"
dt.Rows.Add(dr5)
added the row to datatable
Dim dr4 As DataRow = dt.NewRow()
dr4("Name") = "9000"
dr4("Place") = "Bangalore"
dr4("date") = "1-Aug-2014"
dt.Rows.Add(dr4)
This below part get error
Dim grouped = From groupbyUD In From userdefinedtable In dt.AsEnumerable()Group userdefinedtable By New With { _
Key .placeCol = userdefinedtable("Place") _
}New With { _
Key .ValueUD = groupbyUD.Key, _
Key .ColumnValuesUD = groupbyUD _
}
Dim place As String = ""
Dim [date] As String = ""
Dim tempTable As New DataTable()
Dim slectedFieldsTable As New DataTable()
Dim newRow As DataRow
Dim list As New List(Of Object)()
create the data table
slectedFieldsTable = New DataTable()
slectedFieldsTable.Columns.Add("place")
slectedFieldsTable.Columns.Add("date")
Also below var get the error and grouped also get the error.
For Each keyUD As var In grouped
Console.WriteLine(keyUD.ValueUD.placeCol)
place = DirectCast(keyUD.ValueUD.placeCol, String)
Dim lst As New List(Of DateTime)()
For Each columnValue As var In keyUD.ColumnValuesUD
lst.Add(Convert.ToDateTime(columnValue("date")))
Next
Console.WriteLine(lst.Min())
[date] = DirectCast(Convert.ToString(lst.Min()), String)
slectedFieldsTable.Rows.Add(place, [date])
Next
bind the value data set to list
For Each drin As DataRow In slectedFieldsTable.Rows
list.Add(drin)
Next
tempTable.Columns.Add("place", GetType(String))
tempTable.Columns.Add("date", GetType(String))
For Each drlst As DataRow In list
newRow = tempTable.NewRow()
newRow("place") = drlst.ItemArray(0).ToString()
newRow("date") = drlst.ItemArray(1).ToString()
tempTable.Rows.Add(newRow)
tempTable.AcceptChanges()
Next
Console.ReadLine()
End Sub
End Class
End Namespace
I think following code solve your problem. Replace code with yours.
Dim grouped = From userdefinedtable In dt.AsEnumerable() _
Group userdefinedtable By Key = userdefinedtable("Place") Into Group _
Select ValueUD = Key, ColumnValuesUD = Group
Replace as Var with as Object
For Each keyUD As Object In grouped
Console.WriteLine(keyUD.ValueUD.placeCol)
place = DirectCast(keyUD.ValueUD.placeCol, String)
Dim lst As New List(Of DateTime)()
For Each columnValue As Object In keyUD.ColumnValuesUD
lst.Add(Convert.ToDateTime(columnValue("date")))
Next
Console.WriteLine(lst.Min())
[date] = DirectCast(Convert.ToString(lst.Min()), String)
slectedFieldsTable.Rows.Add(place, [date])
Next

Updating only Last row of datatable to all index of List<T>. Need to convert datatable to List

Dim dt As DataTable = catheter.FetchCatheter()
Dim ct As New EntityObjects.CatheterTypeBO
Dim cList As New List(Of EntityObjects.CatheterTypeBO)
For i As Integer = 0 To dt.Rows.Count - 1
ct.ID = dt.Rows(i)("ID")
ct.Type = dt.Rows(i)("CTYPE")
ct.Active = dt.Rows(i)("ACTIVE").ToString()
cList.Add(ct)
Next
updating all index of cList by last row of dt. Need to convert datatable to List
Try to use AsEnumerable then Last() like:
Dim dt As DataTable = catheter.FetchCatheter()
Dim ct As New EntityObjects.CatheterTypeBO
Dim cList As New List(Of EntityObjects.CatheterTypeBO)
Dim dr as DataRow = dt.AsEnumerable().Last()
ct.ID = dr("ID")
ct.Type = dr("CTYPE")
ct.Active = dr("ACTIVE").ToString()
cList.Add(ct)