Convert c# linq query to vb.net - vb.net

I have some C# LINQ code and would like to convert it to vb.net. Can you help?
var userSessionId= 25;
ProjectsPerUser = db.tbProjekt.Where(s => s.tbUserProjects.Any(x => x.UserId == userSessionId)).ToList();
it was out of this raw sql query:
ProjectsPerUser = db.Database.SqlQuery(Of tbProjekt)("SELECT * FROM [16281468_general].[dbo].[tbProjekt] WHERE Id " _
& "IN (SELECT DISTINCT ProjectId FROM [16281468_general].[dbo].[tbUserProject] WHERE UserId = " & userSessionId & ")").ToList
now I want to convert it to vb.net but I have some problems with that.
That is my current try:
tables within context: tbProjekt and tbUserProjects
Dim dabcon As New production_TextEntitesContext
Dim ProjectsPerUsers As New List(Of tbProjekt)
Dim userSessionId As Integer = 111
ProjectsPerUsers = dabcon.tbProjekt.Where(Function(s) s.tbUserProjects.Any(Function(x) x.UserId = userSessionId)).ToList()
But, I got this error:
Late binding operations cannot be converted to expression tree
on line s.tbUserProjects.Any.

Maybe something like this would help. Just an example
Sub Main()
Dim projects As New List(Of Integer)
projects.Add(1)
projects.Add(2)
projects.Add(3)
Dim users As New Dictionary(Of String, Integer)
users.Add("john", 1)
users.Add("mary", 2)
Dim userName As String = "john"
Dim userProjects = From p In projects
Join u In users On p Equals u.Value
Where u.Key = userName
Select p, u.Key
For Each v In userProjects
Console.WriteLine("user: {0} project: {1}", v.Key, v.p)
Next
Console.ReadLine()
End Sub

Assuming you have navigation properties set up, this should work as well:
Dim userProjects=dabcon.tbUsers.Where(Function(u) u.Key=userName).Select(Function(u) u.Projects))
or query syntax:
Dim userProjects=from u in dabcon.tbUsers
where u.Key=userName
select u.Projects

Related

Issues on loop for retrieve the dynamic sql parameter values from dynamic textboxes

all. I am a new VB.NET beginner. I am facing the issue of how to pass the dynamic SQL parameter values from the dynamic textboxes to search the data. I had added control of dynamic textboxes and labels and would like to search the data on the database table based on the dynamic textboxes value inputted from the user. Currently, I can only able to search the data from 1 dynamic textbox value only.
I want all the values from the dynamic textboxes that the user had been entered can be retrieved, and search the data based on the SQL parameter variable name and value entered by the user.
Can someone give me some solutions on how to solve this problem? I had stuck on this problem for a few days. Thank you for all the help!
What I had tried:
Private Sub FilterData()
Dim count As Integer = 0
'filterdata for radiobutton
Try
For Each TextBox As TextBox In grp2.Controls.OfType(Of TextBox)()
For Each Label As Label In grp2.Controls.OfType(Of Label)()
Using connection As New SqlConnection("connectionString")
'user key in the SQL statement
sql = TextBox1.Text
Dim sql2 As String
sql2 = sql
Dim sp1 As String() = sql.Split(New String() {"where"}, StringSplitOptions.None)
sql = sp1(0) & " where " & Label.Text & " = #parameter or " & Label.Text & " =#parameter"
If (TextBox.Text <> "") Then
count += 1
For j As Integer = 0 To count - 1
Using cmd As New SqlCommand(sql, connection)
cmd.Parameters.AddWithValue("#parameter", TextBox.Text)
'cmd.Parameters.Add("#parameter", SqlDbType.NVarChar, 20).Value = TextBox.Text
connection.Open()
Dim dt As New DataTable()
Dim reader As SqlDataReader
reader = cmd.ExecuteReader()
dt.Load(reader)
DataGridView1.DataSource = dt
End Using
Next
Else
GetData()
End If
'cmd.Dispose()
connection.Close()
End Using
Next
Next
Catch ex As Exception
'MsgBox(ex.Message)
End Try
End Sub
Firstly, if you have a 1:1 correspondence between Labels and TextBoxes then you should not be using two nested For Each loops, because that is going to pair up each and every Label with each and every TextBox. What you should be doing is creating arrays and then using a single For loop to access the pairs of controls:
Dim labels = grp2.Controls.OfType(Of Label)().ToArray()
Dim textBoxes = grp2.Controls.OfType(Of TextBox)().ToArray()
For i = 0 To labels.getUpperBound(0)
Dim label = labels(i)
Dim textBox = textBoxes(i)
'...
Next
As for build the SQL and adding the parameters, I would tend to do it something like this:
Dim labels = grp2.Controls.OfType(Of Label)().ToArray()
Dim textBoxes = grp2.Controls.OfType(Of TextBox)().ToArray()
Dim criteria As New List(Of String)
Dim command As New SqlCommand
For i = 0 To labels.getUpperBound(0)
Dim label = labels(i)
Dim textBox = textBoxes(i)
Dim parameterName = "#" & label.Text.Replace(" ", "_")
criteria.Add($"[{label.Text}] = {parameterName}")
command.Parameters.AddWithValue(parameterName, textBox.Text)
Next
Dim sql = "SELECT * FROM MyTable"
If criteria.Any() Then
sql &= " WHERE " & String.Join(" OR ", criteria)
End If
command.CommandText = sql
I think that you should begin to separate UI and data logic here is an example of implementation:
First you have a table in database:
CREATE TABLE Customer (
Id INT IDENTITY (1, 1) PRIMARY KEY,
FirstName VARCHAR (255) NOT NULL,
LastName VARCHAR (255) NOT NULL,
Phone VARCHAR (25),
Email VARCHAR (255) NOT NULL,
Street VARCHAR (255),
City VARCHAR (50),
State VARCHAR (25),
ZipCode VARCHAR (5)
);
Then you create the underlying entity in VB. Net:
Public Class Customer
Public Property Id As Integer
Public Property FirstName As String
Public Property LastName As String
Public Property Phone As String
Public Property Email As String
Public Property Street As String
Public Property City As String
Public Property State As String
Public Property ZipCode As String
End Class
Data loader
Now you need a data access component that loads records to a list of this above entity here a nice implementation:
Imports System.Data.SqlClient
Public Class CustomerDataAccess
Public Property ConStr As String
Public Sub New(ByVal constr As String)
constr = constr
End Sub
Public Function GetCustomersByCriterias(constraints As Object) As List(Of Customer)
Dim query As String = "SELECT Id, FirstName, LastName, Phone, Email, Street, City, State, ZipCode
FROM [dbo].[Customer] "
Dim result = New List(Of Customer)()
Using con = New SqlConnection(ConStr)
Using cmd = con.CreateCommand()
cmd.CommandType = CommandType.Text
cmd.CommandText = query
'' here the magic to add dynamic criteria coming from constraints
cmd.ApplyConstraints(Of Customer)(constraints)
con.Open()
LoadCustomerData(cmd, result)
End Using
End Using
Return result
End Function
Private Sub LoadCustomerData(ByVal cmd As SqlCommand, ByVal result As List(Of Customer))
Using rdr = cmd.ExecuteReader()
Dim idIdx As Integer = rdr.GetOrdinal("Id")
Dim firstNameIdx As Integer = rdr.GetOrdinal("FirstName")
Dim lastNameIdx As Integer = rdr.GetOrdinal("LastName")
Dim phoneIdx As Integer = rdr.GetOrdinal("Phone")
Dim emailIdx As Integer = rdr.GetOrdinal("Email")
Dim streetIdx As Integer = rdr.GetOrdinal("Street")
Dim cityIdx As Integer = rdr.GetOrdinal("City")
Dim stateIdx As Integer = rdr.GetOrdinal("State")
Dim zipCodeIdx As Integer = rdr.GetOrdinal("ZipCode")
While rdr.Read()
Dim item = New Customer()
item.Id = rdr.GetValueOrDefault(Of Integer)(idIdx)
item.FirstName = rdr.GetValueOrDefault(Of String)(firstNameIdx)
item.LastName = rdr.GetValueOrDefault(Of String)(lastNameIdx)
item.Phone = rdr.GetValueOrDefault(Of String)(phoneIdx)
item.Email = rdr.GetValueOrDefault(Of String)(emailIdx)
item.Street = rdr.GetValueOrDefault(Of String)(streetIdx)
item.City = rdr.GetValueOrDefault(Of String)(cityIdx)
item.State = rdr.GetValueOrDefault(Of String)(stateIdx)
item.ZipCode = rdr.GetValueOrDefault(Of String)(zipCodeIdx)
result.Add(item)
End While
End Using
End Sub
End Class
Extensions methods
Below are extensions methods referenced above that do the magic you are looking for:
DataReader extensions to make it easy to read values from SalDataReader with Dbnull exfeptional case and casting
Module DataReaderExtenions
<Extension()>
Function GetValueOrDefault(Of T)(row As IDataRecord, fieldName As String) As T
Dim ordinal = row.GetOrdinal(fieldName)
Return row.GetValueOrDefault(Of T)(ordinal)
End Function
<Extension()>
Function GetValueOrDefault(Of T)(row As IDataRecord, ordinal As Integer) As T
Return (If(row.IsDBNull(ordinal), Nothing, row.GetValue(ordinal)))
End Function
<Extension()>
Function GetValueOrDefaultSqlite(Of T)(row As IDataRecord, fieldName As String) As T
Dim ordinal = row.GetOrdinal(fieldName)
Return row.GetValueOrDefault(Of T)(ordinal)
End Function
<Extension()>
Function GetValueOrDefaultSqlite(Of T)(row As IDataRecord, ordinal As Integer) As T
Return (If(row.IsDBNull(ordinal), Nothing, Convert.ChangeType(row.GetValue(ordinal), GetType(T))))
End Function
End Module
Command extensions that lets you extract criteria from an anonymous object values:
Imports System.Reflection
Imports System.Runtime.CompilerServices
Module CommandExtensions
<Extension()>
Function AddParameter(command As IDbCommand, name As String, value As Object) As IDataParameter
If command Is Nothing Then Throw New ArgumentNullException("command")
If name Is Nothing Then Throw New ArgumentNullException("name")
Dim p = command.CreateParameter()
p.ParameterName = name
p.Value = If(value, DBNull.Value)
command.Parameters.Add(p)
Return p
End Function
<Extension()>
Function ToDictionary(data As Object) As Dictionary(Of String, Object)
If TypeOf data Is String OrElse data.[GetType]().IsPrimitive Then Return New Dictionary(Of String, Object)()
Return (From [property] In data.[GetType]().GetProperties(BindingFlags.[Public] Or BindingFlags.Instance)
Where [property].CanRead
Select [property]).ToDictionary(Function([property]) [property].Name, Function([property]) [property].GetValue(data, Nothing))
End Function
<Extension()>
Sub ApplyConstraints(Of TEntity)(cmd As IDbCommand, constraints As Object)
If constraints Is Nothing Then Return
Dim dictionary = constraints.ToDictionary()
Dim whereClause = " WHERE "
For Each kvp In dictionary
Dim columnName = kvp.Key
Dim propertyName = kvp.Key
Dim prefix = "#"c
Dim value = kvp.Value
whereClause += $"{columnName} **like** {prefix}{propertyName} AND "
cmd.AddParameter(propertyName, value)
Next
If String.IsNullOrEmpty(whereClause) Then Return
cmd.CommandText += whereClause.Remove(whereClause.Length - 5, 5)
End Sub
End Module
Example:
After coded all these stuff now you can do the following:
Dim DataGridView1 As DataGridView = New DataGridView()
Dim ConStr As String = ConfigurationManager.ConnectionStrings("MyApp").ConnectionString
Dim dal As CustomerDataAccess = New CustomerDataAccess(ConStr)
Dim criterias = New With {.FirstName = "%James%", .LastName = "%Nadin%"}
DataGridView1.DataSource = dal.GetCustomersByCriterias(criterias)
Despite all this code you are still need to bind your textbox (after naming them correctly) to a SearchEntity and use this entity to provide criterias
I hope this material can help you tackle your issue and incite you to improve your architecture & dev skills

Get data from EF by sending type

I managed to get data from entity framework by sending table name as string as below
Public Class EFORMv1(Of t As New)
Dim dx As New EF_ORMv1.MyEntity
Function SelectByKey(Table$,Field$,Value As Object) As IEnumerable(Of t)
Dim s = "SELECT * FROM " + Table + " WHERE " + Field + " = #p1"
Dim r = dx.Database.SqlQuery(Of t)(s, New SqlParameter("#p1",Value))
Return r
End Function
End Class
I am using it like this
Dim x As New EFORMv1(Of EF_ORMv1.CONTACT)
Dim y = x.SelectByKey("CONTACT","NUM",1000).ToList
Me.dataGridView1.DataSource = y
What i am searching for is not sending the table name as string as parameter, but since I send the type in [New EFORMv1(of EF_ORMv1.CONTACT)] so I would like to use it in SelectByKey() function
Is this possible?

Adding User to AD Group in VB.Net (2008)

I needed to add users to Active Directory using VB. I found code that works (mostly), except for assigning the user to a group. I'm fairly certain that the code works, I just don't know the format of the group to pass to it.
Given the code (below), and the image of my AD structure (below that), what is the structure of the GroupName passed to the routine to add the user to the group "Level1/All Users/Level 2/A-K"?
TIA
Public Shared Sub AddUserToGroup(ByVal de As DirectoryEntry, ByVal deUser As DirectoryEntry, ByVal GroupName As String)
Dim deSearch As DirectorySearcher = New DirectorySearcher()
deSearch.SearchRoot = de
deSearch.Filter = "(&(objectClass=group) (cn=" & GroupName & "))"
Dim results As SearchResultCollection = deSearch.FindAll()
Dim isGroupMember As Boolean = False
If results.Count > 0 Then
Dim group As New DirectoryEntry(results(0).Path)
Dim members As Object = group.Invoke("Members", Nothing)
For Each member As Object In CType(members, IEnumerable)
Dim x As DirectoryEntry = New DirectoryEntry(member)
Dim name As String = x.Name
If name <> deUser.Name Then
isGroupMember = False
Else
isGroupMember = True
Exit For
End If
Next member
If (Not isGroupMember) Then
group.Invoke("Add", New Object() {deUser.Path.ToString()})
End If
group.Close()
End If
Return
End Sub
According to your input from your comment I set up this Sub for you.
You havn't clarified the level below Level2 so I just called it Level3.
This function already enables User as a disabled User is useless...
References:
Imports System.DirectoryServices
How to Use:
CreateUser("Doe", "John")
Method:
Public Sub CreateUser(ByVal givenname As String, ByVal surname As String)
Dim dom As New DirectoryEntry()
Dim ou As DirectoryEntry = dom.Children.Find("OU=All Users")
Dim ou2 As DirectoryEntry = ou.Children.Find("OU=Level2")
Dim ou3 As DirectoryEntry = ou2.Children.Find("OU=Level3")
Dim firstLetter As String = givenname.Substring(0, 1)
Dim ou4 As DirectoryEntry
If firstLetter Like "*[A-K]*" Then
ou4 = ou3.Children.Find("OU=A-K")
Else
ou4 = ou3.Children.Find("OU=L-Z")
End If
Dim ADuser As DirectoryEntry = ou4.Children.Add("CN=" & givenname & "\, " & surname, "user")
ADuser.CommitChanges()
'The User is now created. Most people forget to enable their users so I'll put it in here too
'UF_DONT_EXPIRE_PASSWD 0x10000
Dim exp As Integer = CInt(ADuser.Properties("userAccountControl").Value)
ADuser.Properties("userAccountControl").Value = exp Or &H1
ADuser.CommitChanges()
'UF_ACCOUNTDISABLE 0x0002
Dim val As Integer = CInt(ADuser.Properties("userAccountControl").Value)
ADuser.Properties("userAccountControl").Value = val And Not &H2
ADuser.CommitChanges()
End Sub
See my answer in this post for basic knowledge of interaction with AD and LDAP.

Group DataSet Column Values into Comma Separated String using LINQ

How do I combine column values in a dataset using LINQ into a single string with comma separated values in VB.NET ?
I have one table with following structure
ID Name
728 Jim
728 Katie
728 Rich
How do I combine these into a single row like following
ID Name
728 Jim,Katie,Rich
Please note I am using a LINQ to Dataset so please respond in the applicable syntax.
Here is an example (using LINQ to objects, but should be easy to adjust for LINQ to DataSet):
Class Record
Public Property ID As Integer
Public Property Name As String
Sub New(id As Integer, name As String)
Me.ID = id
Me.Name = name
End Sub
End Class
Sub Main()
Dim recordList As New List(Of Record)
recordList.Add(New Record(728, "Jim"))
recordList.Add(New Record(728, "Katie"))
recordList.Add(New Record(728, "Rich"))
recordList.Add(New Record(729, "John"))
recordList.Add(New Record(729, "Michael"))
Dim v = From r As Record In recordList
Group By ID = r.ID Into Records = Group
Select ID, Name = String.Join(","c, Records.Select(Function(x) x.Name))
End Sub
This should do what you want:
Dim result = list.GroupBy(Function(a) a.ID) _
.Select(Function(g) New With {.ID = g.Key, .csvList = g.Select(Function(n) n.Name) _
.Aggregate(Function(accumulation, current) accumulation + "," + current)}) _
.ToList()
This is an example using LINQ to Dataset:
Dim grouped =
From row In dt.AsEnumerable()
Group row By id = row.Field(Of Integer)("ID") Into Group
Select ID, Name = String.Join(",", From i In Group Select i.Field(Of String)("Name"))
pretty late but i also ran into same problem and this is my solution. Hope this helps someone
Dim grouped =
a.AsEnumerable().
GroupBy(Function(row) row.Field(Of Integer)("ID")).
Select(Function(group, ID)
Return New With
{
.ID= ID,
.Name= String.Join(",", group.Select(Function(row) row.Field(Of String)("Name")))
}
End Function)

LINQ filtering list objects

I have list object and I need to check id in a comma separated string using LINQ in VB.NET, something like this:
dim strId as String = "1,2,3,5,"
dim myList = from objmylist where objmylist.id in (strId)
dim strId as String = "1,2,3,5,"
dim IDs as String() = strId.Split(",")
dim myList = from objmylist where IDs.Contains(objmylist.id)
select objmylist
dim strId as String = "1,2,3,5,"
dim myList = from objmylist where strId.split(",").Contains(objmylist.id)
untested, but should do the trick I guess.
Your code is perfectly fine if you split the string before using it in the linq
In C# you would do this:
string strIDs = "1,2,3,5,";
string[] arrIDs = strIDs.Split(",");
var myList = objmylist.Where(o => arrIDs.Contains(o.id));
Perhaps you can understand this enough to translate it into VB
Using C#,
int[] productList = new int[] { 1, 2, 3, 4 };
var myProducts = from p in db.Products
where productList.Contains(p.ProductID)
select p;
using VB.NET,
Dim productList As Integer() = New Integer() {1, 2, 3, 4}
Dim myProducts = From p In db.Products Where productList.Contains(p.ProductID)
In Reference from Creating SQL IN Queries using LINQ