I have a listbox on my xaml form that I bound to a List(Of MyType) property. I populated this list like so:
Dim fields As List(Of CheckableFields) = New List(Of CheckableFields)
Using context As ITIPEntities = New ITIPEntities()
Try
Dim propertyInfoList As List(Of PropertyInfo) = GetType(PC).GetProperties().ToList()
For Each pI In propertyInfoList
If (pI.PropertyType <> GetType(EntityState) _
And pI.PropertyType <> GetType(EntityKey) _
And pI.PropertyType <> GetType(EntityCollection(Of DiskDrive)) _
And pI.PropertyType <> GetType(EntityCollection(Of Memory)) _
And pI.PropertyType <> GetType(EntityCollection(Of Monitor)) _
And pI.PropertyType <> GetType(EntityCollection(Of Network)) _
And pI.PropertyType <> GetType(EntityCollection(Of Processor))) Then
fields.Add(New CheckableFields(pI.Name))
End If
Next
Catch ex As Exception
End Try
End Using
Now I'm at the point where the user selects the fields they want included in a report and I need to iterate over the required fields. This is my linq query:
For Each checkedField In _requiredFields
If checkedField.IsChecked Then
If checkedField.FieldData IsNot Nothing AndAlso checkedField.FieldData.Trim IsNot String.Empty Then
Dim fieldData As String = checkedField.FieldData
Dim name As String = checkedField.Name
lquery = From comp In lquery Where CType(comp.GetType.GetProperty(name).GetValue(comp, Nothing), String).ToUpper.Contains(fieldData.ToUpper) Select comp
End If
End If
Next
Which throws the exception that linq doesn't recognize the GetValue method.
How can I get the property values dynamically?
Edit:
I couldn't find a way to do this with Linq to Entities, but I did find a way without Linq that works for me:
For Each field In _requiredFields
If field.IsChecked Then
reportGenerator.AllFields.Add(field.Name)
If field.FieldData IsNot Nothing Then
For i As Integer = pcs.Count - 1 To 0 Step -1
Dim compPropertyValue As String = CType(pcs(i).GetType().GetProperty(field.Name).GetValue(pcs(i), Nothing), String).ToUpper()
If Not compPropertyValue.Contains(field.FieldData.ToUpper()) Then
pcs.RemoveAt(i)
End If
Next i
End If
End If
Next
This construct is not supported in LINQ-to-Entities. It is a designed limitation.
Try using Entity SQL instead as shown in the following example:
"SELECT VALUE comp From COMPs AS comp WHERE comp." & name & ".ToUpper().Contains(" & fieldData & ".ToUpper()"
Related
I try to buid a method to add a where clause to a Linq-to-SQL request (return an IQueryable). I try several methods but always use ToString, Indexof... but this result is a sql request take all element and the filter made in linq. I see request in SQL Server profiler.
I want a method to do it with result is a sql request with where include inside
I work in Visual Studio 2017 with SQL Server 2016. I code in vb.net
I see an interesting thing in linq dynamic library. But I can't to adapt to my situation
<Extension()> _
Public Function Where(ByVal source As IQueryable, ByVal predicate As String, ByVal ParamArray values() As Object) As IQueryable
If source Is Nothing Then Throw New ArgumentNullException("source")
If predicate Is Nothing Then Throw New ArgumentNullException("predicate")
Dim lambda As LambdaExpression = DynamicExpression.ParseLambda(source.ElementType, GetType(Boolean), predicate, values)
Return source.Provider.CreateQuery( _
Expression.Call( _
GetType(Queryable), "Where", _
New Type() {source.ElementType}, _
source.Expression, Expression.Quote(lambda)))
End Function
But I don't need all this complex strucutre. It's some years I buid my utilities. But Need to upgrade it. Here my code of my utilities
<Extension()>
Public Function Where(ByVal source As IQueryable, ByVal predicate As String) As IQueryable
Dim param = Expression.Parameter(GetType(String), "x")
Return source.Provider.CreateQuery(
Expression.Call(
GetType(Queryable), "Where",
New Type() {source.ElementType},
source.Expression, Expression.Quote(Expression.Lambda(Expression.Constant(predicate), param))))
End Function
Public Function TFOAppliqueFiltreTri(Of T, MaClassDatas As Class)(Origins As IQueryable(Of T), ByVal MesDonnees As TableFullOption.PagerTabEnCours(Of MaClassDatas)) As IQueryable(of T)
Dim retour As New TableFullOption.LstRetour
'Colonne de filtre
Dim strWh As String = ""
Dim Filtredrecords As IQueryable(Of T)
For Each Sort In MesDonnees.MesOptions
Dim colName = Sort.ColName
If strWh.Length > 0 Then strWh = strWh & " AND "
strWh = strWh & String.Format(colName & " like '%{0}%'", Sort.Search)
Next
If strWh.Length > 0 Then
Filtredrecords = Origins.Where(strWh) '<- Here call Where
Else
Filtredrecords = Origins
End If
Return Filtredrecords
End Function
I get this error:
Aucune méthode générique 'Where' sur le type 'System.Linq.Queryable' n'est compatible avec les arguments de type et les arguments fournis..
Then my problem is to write correctly lambda expression. My predicate argument is : Column1 like '%aaa%'. I want rewrite where method of dynamicLinq to accept string argument :Column1 like '%aaa%' directly
Thanks for your help
Finally after lot of reading in google and few feelings and certainly lot of chance.
Public Function Where(Of TEntity)(source As IQueryable(Of TEntity), searchColumn As List(Of String), searchValue As String) As IQueryable(Of TEntity)
Dim cond As Expression = Nothing
Dim ParamExpr = Expression.Parameter(GetType(TEntity), "x")
Dim conCat2 = GetType(String).GetMethod("Concat", New Type() {GetType(String), GetType(String)})
Dim conCat4 = GetType(String).GetMethod("Concat", New Type() {GetType(String), GetType(String), GetType(String), GetType(String)})
Dim Delim = Expression.Constant("/")
Dim DateName = GetType(SqlFunctions).GetMethod("DateName", New Type() {GetType(String), GetType(Nullable(Of DateTime))})
Dim DatePart = GetType(SqlFunctions).GetMethod("DatePart", New Type() {GetType(String), GetType(Nullable(Of DateTime))})
Dim DblToString = GetType(SqlFunctions).GetMethod("StringConvert", New Type() {GetType(Nullable(Of Double))})
For Each cn In searchColumn
For Each colName In cn.Split("|")
If Not colName.estVide Then
Dim body As Expression = ParamExpr
For Each member In colName.Split(".")
body = Expression.PropertyOrField(body, member)
Next
Dim Tostr As Expression
If body.Type.FullName.Contains("String") Then
Tostr = body
ElseIf body.Type.FullName.Contains("DateTime") Then
Dim day = Expression.Call(Expression.Call(conCat2, Expression.Constant("0"), Expression.Call(DateName, Expression.Constant("day"), body)), "Substring", Nothing, Expression.Constant(0), Expression.Constant(2))
Dim Month = Expression.Call(DatePart, Expression.Constant("MM"), body)
Dim toDouble = Expression.Convert(Month, GetType(Nullable(Of Double)))
Dim mois = Expression.Call(conCat2, Expression.Constant("0"), Expression.Call(Expression.Call(DblToString, toDouble), "Trim", Nothing))
Dim an = Expression.Call(DateName, Expression.Constant("year"), body)
Tostr = Expression.Call(conCat2, Expression.Call(conCat4, day, Delim, mois, Delim), an)
Else
Tostr = Expression.Call(body, "Convert.ToString", Nothing)
'Tostr = Expression.Convert(body, GetType(String))
End If
Dim condPart = Expression.Call(Expression.Call(Tostr, "ToLower", Nothing), "Contains", Nothing, Expression.Call(Expression.Constant(searchValue), "ToLower", Nothing))
If cond Is Nothing Then
cond = condPart
Else
cond = Expression.OrElse(cond, condPart)
End If
End If
Next
Next
Return source.Provider.CreateQuery(Of TEntity)(Expression.Call(GetType(Queryable), "Where", New Type() {GetType(TEntity)}, source.Expression, Expression.Lambda(cond, ParamExpr)))
End Function
Now I've dynamic filter which generated a SQL request with complete clause where
I have a functionality which saves the information from a webform to the database, which is working fine.
This is my code for save functionality in Onspec.aspx.vb page
Public Sub SaveClick(ByVal sender As Object, ByVal e As System.EventArgs)
If Not Page.IsValid Then
litMessage.Text = ""
Exit Sub
End If
Try
Dim sName As String = ""
With EmployerCandidate
.employerid = Master.Employer.ID
.employeruserid = 0
Try
.CVID = DocId
Catch
End Try
.Name = uxName.Text
.SurName = uxSurname.Text
Try
.PostCode = uxPostcode.Text
Catch ex As Exception
End Try
.Email = uxEmail.Text
Try
.MobileNo = uxMobileNo.Text
Catch ex As Exception
End Try
.OnSpec = True
.OnSpecType = uxOnSpecCategory.SelectedItem.Text
.Source = uxSourceID.SelectedItem.Text
.LastEmployer = uxEmployer.Text
.LastJobTitle = uxJobtitle.Text
.Profile = uxProfile.Text.Trim
End With
' email()
ResetForm()
panForm.Visible = False
panUpload.Visible = True
uxSubmit.Visible = False
uxUpload.Visible = True
litMessage.Text = "Thank you for submitting your details! We'll be in touch when appropriate vacancy arises. <a href='#' onclick='parent.$.colorbox.close()'>Close</a>"
UploadPanel.Visible = False
Response.Redirect("onspec-complete.aspx?e=" & Master.Employer.ID)
Catch ex As Exception
litMessage.Text = Core.Helper.FancyMessage("Error as occurred - " & ex.Message.ToString, "ERROR")
End Try
End Sub
Now, I want to send emails along with saving the data in the database so I added the following lines of code before ResetForm().
Dim specmatch As DataRow = DB.GetRow("SELECT TOP 1 name,email,password FROM [user] usr JOIN employeruser empUsr ON usr.id = empUsr.userid WHERE empUsr.empusertype = 1 AND empUsr.employerid = #eid ", DB.SIP("eid", LocalHelper.UserEmployerID))
If my query returns a value then I want to send email by calling the email function.
If specmatch IsNot Nothing Then
email()
End If
But in this line of code the employerid value is sometimes empty. It can't pick the id therefore it is returning an empty row. And therefore it's not calling the email function.
This id is the same as
.employerid = Master.Employer.ID
But if I replace the LocalHelper.UserEmployerID with Master.Employer.ID the form gives an error:
Object reference not set to an instance of an object.
employerid is an integer value.
I have also tried to add the following lines of code in this page(Onspec.aspx.vb)
Public ReadOnly Property EmployerId() As Integer
Get
Return Master.Employer.ID
End Get
End Property
But I get the same error:
Object reference not set to an instance of an object.
The above lines of code does not make any difference.
So I replaced Master.Employer.ID with LocalHelper.UserEmployerID
Where in localhelper.vb file (under appcode folder) it is determining employerid from the website with following lines of code.
Public Shared Function UserEmployerID() As Integer
If HttpContext.Current.Items("lh_useremployerid") Is Nothing Then
If LocalHelper.UserTypeCode = "e" Then
HttpContext.Current.Items("lh_useremployerid") = Core.DB.GetInteger("SELECT employerid FROM employeruser WHERE userid = " & LocalHelper.UserID)
Else
HttpContext.Current.Items("lh_useremployerid") = 0
End If
End If
Return HttpContext.Current.Items("lh_useremployerid")
End Function
These lines of code has been used in many places and works perfectly fine. In this case as well, it was working fine last Friday and now it's not. There was no changes made.
This is my email function
Private Sub email()
Dim strCandidateName As String = uxName.Text.Trim & " " & uxSurname.Text.Trim
Dim strCandidateSurname As String = uxSurname.Text
Dim strCandidateEmail As String = uxEmail.Text.Trim
Dim strCandidatePhone As String = uxMobileNo.Text.Trim
Dim strCPass As String = "mpb123"
Dim strContactType As String = "Speculative Application has been submited on the category of " & uxOnSpecCategory.SelectedItem.Text
Dim strContactMessage As String = uxProfile.Text.Trim
'''''''''''''''''''variable
Dim qq As String = String.Format("Select top 1 name, email, password FROM [user] WHERE id in (Select userid FROM employeruser WHERE empusertype=1 and employerid= " & LocalHelper.UserEmployerID & ")")
Dim drow As DataRow = Core.DB.GetRow(qq)
Dim semail As String = drow.Item("email").ToString
Dim sname As String = drow.Item("name").ToString
Dim spass As String = drow.Item("password").ToString
'''''''''''''''''''variable
Dim Email As Core.Email
'New Onspec Candidate Email sent to EmployerUser who is assigned to receive onspec email
Email = New Core.Email
With Email
.ContentID = 99
.Replacement("ContactName", strCandidateName)
.Replacement("ContactEmail", strCandidateEmail)
.Replacement("ContactTelephone", strCandidatePhone)
.Replacement("ContactType", strContactType)
.Replacement("ContactMessage", strContactMessage)
.Replacement("AdminContactName", sname)
.Replacement("AdminContactEmail", semail)
.Replacement("SiteName", LocalHelper.AppSetting("sitename"))
Dim attachments As New Generic.List(Of String)
If EmployerCandidate.CVID > 0 Then
Dim doc As New Document(EmployerCandidate.CVID)
attachments.Add(doc.PathOnDisc)
End If
.Attachments = Join(attachments.ToArray(), ";")
.Send()
End With
End Sub
GetRow function is defined in my database.vb page like following which is also used in many other places.
Shared Function GetRow(ByVal selectQueryText As String, ByVal ParamArray params As SqlParameter()) As DataRow
Return GetRowFromDB(selectQueryText, CommandType.Text, params)
End Function
And
Shared Function GetRowFromDB(ByVal selectCommandText As String, ByVal selectCommandType As CommandType, ByVal ParamArray params As SqlParameter()) As DataRow
Dim conn As SqlConnection = Nothing
Try
conn = GetOpenSqlConnection()
Return GetRowFromDB(conn, selectCommandText, selectCommandType, params)
Finally
If conn IsNot Nothing Then conn.Dispose()
End Try
End Function
Please suggest ways on how I can organize my code so that it works all the time.
I am hopeing someone can help me here with a recursive function I have that is not returning either true or false as I would have espected it to. The function loops through a Active Directory group for its members and then calls itself if it encounters any groups within the membership in order to gets its members as well. I am trying to return either true or false based on if any errors were encountered but not haveing any luck at all. It appears to just hang and never return back to the primary calling sub that starts the recursive function. Below is my code I am using:
Private Sub StartAnalysis(ByVal grp As String, ByVal grpdn As String, ByVal reqid As String)
Dim searchedGroups As New Hashtable
'prior work before calling sub
searchedGroups.Add(grp, 1)
Dim iserror As Boolean = GetGroupMembers(grpdn, searchedGroups, reqid)
If iserror = False Then
'do stuff
Else
'do stuff
End If
'cleanup
End Sub
Public Function GetGroupMembers(ByVal groupSearch As String, ByVal searchedGroups As Hashtable, ByVal requestID As String) As Boolean
Dim iserror As Boolean = False
Try
Dim lastQuery As Boolean = False
Dim endLoop As Boolean = False
Dim rangeStep As Integer = 999
Dim rangeLow As Integer = 0
Dim rangeHigh As Integer = rangeLow + rangeStep
Do
Dim range As String = "member"
If lastQuery = False Then
range = String.Format("member;range={0}-{1}", rangeLow, rangeHigh)
Else
range = String.Format("member;range={0}-*", rangeLow)
endLoop = True
End If
Dim group As SearchResult = QueryObject(groupSearch, range)
Dim groupCN As String = group.Properties("cn")(0).ToString
If group.Properties.Contains(range) Then
For Each member As Object In group.Properties(range)
Dim user As SearchResult = QueryObject(member.ToString, "member")
Dim userCN = user.Properties("cn")(0).ToString
If Not user.Properties.Contains("member") Then
Dim userMail = String.Empty
If user.Properties.Contains("mail") Then
userMail = user.Properties("mail")(0).ToString
End If
userCN = userCN.Replace("'", "''")
Dim qry As String = _
"INSERT INTO group_analysis_details (request_id, member_name, member_email, member_group) " & _
"values ('" & requestID & "', '" & userCN & "', '" & userMail & "', '" & groupCN & "')"
Dim sqlConn As SqlConnection = New SqlConnection(cs)
Dim sqlCmd As SqlCommand = New SqlCommand(qry, sqlConn)
sqlConn.Open()
sqlCmd.ExecuteNonQuery()
sqlConn.Close()
sqlCmd.Dispose()
sqlConn.Dispose()
Else
If Not searchedGroups.ContainsKey(userCN) Then
searchedGroups.Add(userCN, 1)
iserror = GetGroupMembers(user.Properties("distinguishedname")(0).ToString, searchedGroups, requestID)
If iserror = True Then Return iserror
Else
searchedGroups(userCN) += 1
End If
End If
Next
Else
lastQuery = True
End If
If lastQuery = False Then
rangeLow = rangeHigh + 1
rangeHigh = rangeLow + rangeStep
End If
Loop While endLoop = False
Return iserror
Catch ex As Exception
myEvents.WriteEntry("Error while analyzing the following group: " & groupSearch & vbCrLf & vbCrLf & _
"Details of the error are as follows: " & ex.Message, EventLogEntryType.Error)
Return True
End Try
End Function
Hopefully someone can point out where I might be making my error is this.
Thanks,
Ron
Generally if you're using a 'Do...Loop While' and manually setting the exit condition inside the loop it's very easy to get stuck in an infinite loop which is what causes the program to hang.
It looks like you're not setting endloop = True in all circumstances. Try changing it to an Exit Do and adding one to each of the various conditions you have. A bit of trial and error will be required to get it just right.
Also to make your life easier extract the database insert code into a seperate function and call it when needed.
This function loops all properties of an object to create the updatequery to save te object to the DB.
We had to make some changes to it because of the introduction of nullable properties.
If the property is nullable we would like to check the 'HasValue' property.
This does works when it has a value. When the property has no value we get an 'Non-static method requires a target'-error at the CBool-line
Any suggestions?
An other way to check the 'HasValue'-prop of a property using reflection?
Thanks.
Private Function GetUpdateQuery(ByVal obj As Object, ByRef params As List(Of SqlParameter), Optional ByVal excl As String() = Nothing) As String
Dim sql As String = String.Empty
Dim props As PropertyInfo() = obj.GetType().GetProperties
If excl Is Nothing Then
excl = New String() {}
End If
For Each prop As PropertyInfo In props
Try
If Not excl.Contains(prop.Name) And prop.CanWrite = True Then
sql &= String.Format("{0} = #{1},", prop.Name, prop.Name)
Dim param As SqlParameter
Dim value As Object
If prop.PropertyType.IsGenericType AndAlso prop.PropertyType.GetGenericTypeDefinition() = GetType(Nullable(Of )) Then
If CBool(prop.PropertyType.GetProperty("HasValue").GetValue(prop.GetValue(obj, Nothing), Nothing)) Then
value = prop.GetValue(obj, Nothing)
Else
value = DBNull.Value
End If
Else
If prop.GetValue(obj, Nothing) = Nothing Then
value = DBNull.Value
Else
value = prop.GetValue(obj, Nothing)
End If
End If
param = ConnSql.CreateParameter("#" & prop.Name, value)
params.Add(param)
End If
Catch ex As Exception
End Try
Next
sql = sql.Substring(0, sql.Length - 1)
Return sql
End Function
You do not need the following If. You can remove it.
If prop.PropertyType.IsGenericType AndAlso prop.PropertyType.GetGenericTypeDefinition() = GetType(Nullable(Of )) Then
BUT you do need to fix the following If:
If prop.GetValue(obj, Nothing) = Nothing Then
to
If prop.GetValue(obj, Nothing) IS Nothing Then
--
Complete code:
Private Function GetUpdateQuery(ByVal obj As Object, ByRef params As List(Of SqlParameter), Optional ByVal excl As String() = Nothing) As String
Dim sql As String = String.Empty
Dim props As PropertyInfo() = obj.GetType().GetProperties
If excl Is Nothing Then
excl = New String() {}
End If
For Each prop As PropertyInfo In props
If Not excl.Contains(prop.Name) And prop.CanWrite = True Then
sql &= String.Format("{0} = #{1},", prop.Name, prop.Name)
Dim param As SqlParameter
Dim value As Object
If prop.GetValue(obj, Nothing) Is Nothing Then
value = DBNull.Value
Else
value = prop.GetValue(obj, Nothing)
End If
param = ConnSql.CreateParameter("#" & prop.Name, value)
params.Add(param)
End If
Next
sql = sql.Substring(0, sql.Length - 1)
Return sql
End Function
I'm trying to compare two datatables and I'm doing some tests using DataTable.Select on two identical datatables:
Using DT_NewData As DataTable = DT_DBData.Copy
For x As Short = 0 To DT_NewData.Rows.Count - 1
Dim SelRows As DataRow() = DT_DBData.Select( _
"Type='" & DT_NewData.Rows(x)("Type") & "'" & _
" AND In_Date='" & DT_NewData.Rows(x)("In_Date") & "'" & _
" AND Out_Date='" & DT_NewData.Rows(x)("Out_Date") & "'")
Next
But SelRows.Length is always 0. What's wrong in my code?
Although is a little strange the copy of the table, try this:
Suppose that Type is String
Imports Microsoft.VisualBasic
Imports System.Linq
Module StartupModule
Sub Main()
' Declare the table.
Dim originalDataTable As New DataTable
' Declare the table columns.
With originalDataTable.Columns
.Add("Type", GetType(String))
.Add("InDate", GetType(DateTime))
.Add("OutDate", GetType(DateTime))
End With
' Delegate to add rows.
Dim addRow As Action(Of String, DateTime?, DateTime?) = Sub(text, inDate, outDate)
Dim newRow As DataRow = originalDataTable.NewRow()
With newRow
If (Not String.IsNullOrEmpty(text)) Then
.SetField(Of String)("Type", text)
End If
If (inDate.HasValue) Then
.SetField(Of DateTime?)("InDate", inDate.Value)
End If
If (outDate.HasValue) Then
.SetField(Of DateTime?)("OutDate", outDate.Value)
End If
End With
originalDataTable.Rows.Add (newRow)
End Sub
' Adding rows to the table.
addRow("type1", #2/2/2017#, Nothing)
addRow(Nothing, #1/25/2016#, Nothing)
addRow(Nothing, Nothing, #1/30/2016#)
' Copy the table
Dim copiedDataTable As DataTable = originalDataTable.Copy
' Loop through copied table rows.
For i As Integer = 0 To copiedDataTable.Rows.Count - 1
Dim type As String = copiedDataTable.Rows(i).Field(Of String)("Type")
Dim inDate As DateTime? = copiedDataTable.Rows(i).Field(Of DateTime?)("InDate")
Dim outDate As DateTime? = copiedDataTable.Rows(i).Field(Of DateTime?)("OutDate")
' Using DataTable Select.
Dim filter As String = String.Format("{0} {1} {2}",
If(type Is Nothing, "( Type Is Null )", String.Format("( Type = '{0}' )", type)),
If(Not inDate.HasValue, "And ( InDate Is Null )", String.Format("And ( InDate = '{0}' )", inDate.Value.ToString())),
If(Not outDate.HasValue, "And ( OutDate Is Null )", String.Format("And ( OutDate = '{0}' )", outDate.Value.ToString())))
Dim usingSelectRows As DataRow() = originalDataTable.Select(filter)
Console.WriteLine("usingSelectRows.Count = {0}", usingSelectRows.Count)
' Using Linq.
Dim typeSelector As Func(Of DataRow, Boolean) = Function(r)
If (IsNothing(type)) Then
Return IsNothing(r.Field(Of String)("Type"))
Else
Return r.Field(Of String)("Type") = type
End If
End Function
Dim inDateSelector As Func(Of DataRow, Boolean) = Function(r)
If (Not inDate.HasValue) Then
Return Not r.Field(Of DateTime?)("InDate").HasValue
Else
Return r.Field(Of DateTime?)("InDate").GetValueOrDefault.CompareTo(inDate.GetValueOrDefault) = 0
End If
End Function
Dim outDateSelector As Func(Of DataRow, Boolean) = Function(r)
If (Not outDate.HasValue) Then
Return Not r.Field(Of DateTime?)("OutDate").HasValue
Else
Return r.Field(Of DateTime?)("OutDate").GetValueOrDefault.CompareTo(outDate.GetValueOrDefault) = 0
End If
End Function
Dim usingLinqRows = From r In originalDataTable.AsEnumerable
Where
(typeSelector(r)) AndAlso
(inDateSelector(r)) AndAlso
(outDateSelector(r))
Select r
Console.WriteLine("usingLinqRows.Count = {0}", usingLinqRows.Count)
Console.WriteLine()
Next
Console.ReadLine()
End Sub
End Module
Always use the Field extension of DataRow to retrieve data.