Linq return result as list - vb.net

Hi I am stuck with return the linq result as list. I try to convert but failed to return as the list. Below is my code. Please help. Thanks
Public Function GetConfigList(ByVal aConfig As TT_GENERAL_CONFIGURATION) As List(Of Config)
Dim Data = From p In Db.TT_GENERAL_CONFIGURATION _
Select p
If Data IsNot Nothing Then
ConvertGeneralConfig(Data)
Else
Return Nothing
End If
End Function
Private Function ConvertGeneralConfig(ByVal aConfig As TT_GENERAL_CONFIGURATION) As List(Of Config)
Dim pConfig As New Config
pConfig.ConfigID = aConfig.INTERNAL_NUM
pConfig.ConfigType = aConfig.CONFIG_TYPE
pConfig.ConfigName = aConfig.CONFIG_NAME
pConfig.ConfigValue = aConfig.CONFIG_VALUE
Return pConfig
End Function

Seems like you might want to use
If Data IsNot Nothing Then
Return ConvertGeneralConfig(Data)
Else
Return Nothing
End If

If you only expect one result - then use First() or a FirstOrDefault()
Dim Data = (From p In Db.TT_GENERAL_CONFIGURATION _
Select p)
.FirstOrDefault();
your Data now only contains the first element of the result. If none was found Data is nothing.
UPDATE
If you want your function to return a list then you have to create a list, and return it:
Private Function ConvertGeneralConfig(ByVal aConfig As TT_GENERAL_CONFIGURATION) As List(Of Config)
Dim pConfig As New Config
pConfig.ConfigID = aConfig.INTERNAL_NUM
pConfig.ConfigType = aConfig.CONFIG_TYPE
pConfig.ConfigName = aConfig.CONFIG_NAME
pConfig.ConfigValue = aConfig.CONFIG_VALUE
Dim lst As New List(Of Config) 'Creates a list
lst.Add(pConfig) ' add the object to the list
Return lst ' returns the list
End Function

Related

Creating an object in VB.NET behaves differently on different SQL servers

I have following code which is behaving differently on different servers. In the below method if i write this line of code:
Dim customerPositionsFromPaid = vwCustomerPositionInPaid.SelectAll().Where(conditions).Select(Function(o) New CustomerPositionFromPaidDto(o.FundingYearId.Value, o.DsoId.Value, o.CustomerId.Value, o.CustomerPosition.Value)).ToList()
it returns result on one sql instance but does not return result on other sql instance.
However if i replace the above line with the following, it returns result on both sql instances.
Dim customerPositionsFromPaid = vwCustomerPositionInPaid.
SelectAll().
Where(conditions).
Select(Function(o) New CustomerPositionFromPaidDto() With {.FundingYearId = o.FundingYearId.Value, .DsoId = o.DsoId.Value, .CustomerId = o.CustomerId.Value, .CustomerPosition = o.CustomerPosition.Value}).
ToList()
Could it be because sql server instances have different settings or it's something to do with the code itself?
--Function
Private Shared Function GetCustomerPositionsFromPaid(ByVal customerID As Integer, ByVal fundingYearID As Integer) As IEnumerable(Of CustomerPositionFromPaidDto)
Dim conditions = PredicateBuilder.True(Of vwCustomerPositionInPaid)()
conditions = conditions.And(Function(o) o.CustomerId.Equals(customerID))
conditions = conditions.And(Function(o) o.FundingYearId.Equals(fundingYearID))
conditions = conditions.And(Function(o) o.DsoId.HasValue)
'Dim customerPositionsFromPaid = vwCustomerPositionInPaid.SelectAll().Where(conditions).Select(Function(o) New CustomerPositionFromPaidDto(o.FundingYearId.Value, o.DsoId.Value, o.CustomerId.Value, o.CustomerPosition.Value)).ToList()
'Dim customerPositionsFromPaid = vwCustomerPositionInPaid.SelectAll().Where(conditions).Select(Function(o) New With {.FundingYearId = o.FundingYearId.Value, .DsoId = o.DsoId.Value, .CustomerId = o.CustomerId.Value, .CustomerPosition = o.CustomerPosition.Value}).ToList().Select(Function(o) New CustomerPositionFromPaidDto(o.FundingYearId, o.DsoId, o.CustomerId, o.CustomerPosition)).ToList()
Dim customerPositionsFromPaid = vwCustomerPositionInPaid.
SelectAll().
Where(conditions).
Select(Function(o) New CustomerPositionFromPaidDto() With {.FundingYearId = o.FundingYearId.Value, .DsoId = o.DsoId.Value, .CustomerId = o.CustomerId.Value, .CustomerPosition = o.CustomerPosition.Value}).
ToList()
Return customerPositionsFromPaid
End Function
--Select All
Public Shared Function [SelectAll](ByVal conditions As Expression(Of Func(Of T, Boolean))) As IEnumerable(Of T)
Return [SelectAll]().Where(conditions)
End Function
Public Shared Function [SelectAll]() As IQueryable(Of T)
Return Table
End Function
Private Shared ReadOnly Property Table() As Table(Of T)
Get
Return Context.GetTable(Of T)()
End Get
End Property
I manage to solve the above by writing the following code. Looks like because customerid and fundingyearid are nullable objects, i had to use .Value attribute but still not sure why the previous code will work on one server and not on the other one.
Private Shared Function GetCustomerPositionsFromPaid(ByVal customerID As Integer, ByVal fundingYearID As Integer) As IEnumerable(Of CustomerPositionFromPaidDto)
Dim conditions = PredicateBuilder.True(Of vwCustomerPositionInPaid)()
conditions = conditions.And(Function(o) o.CustomerId.Equals(customerID.Value))
conditions = conditions.And(Function(o) o.FundingYearId.Equals(fundingYearID.Value))
conditions = conditions.And(Function(o) o.DsoId.HasValue)
Dim customerPositionsFromPaid = vwCustomerPositionInPaid.
SelectAll().
Where(conditions).
Select(Function(o) New CustomerPositionFromPaidDto() With {.FundingYearId = o.FundingYearId.Value, .DsoId = o.DsoId.Value, .CustomerId = o.CustomerId.Value, .CustomerPosition = o.CustomerPosition.Value}).
ToList()
Return customerPositionsFromPaid
End Function

Return 2 values from function vb.net

What I want is to return 2 values from the database with a function and then store the values in variables so I can work with them. This is my code.
Function Buscar_Registro(ByVal xId As Integer) As String
Dim a, b As String
'convertir cadena
Dim Id As Integer
Id = xId
'conexión
Dim Conexion As OleDbConnection = New OleDbConnection
Conexion.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\Visual\2000Phrases\2000 Phrases.accdb"
'cadena SQL
Dim CadenaSQL As String = "SELECT * FROM Data WHERE Id = " & Id
'Adaptador
Dim Adaptador As New OleDbDataAdapter(CadenaSQL, Conexion)
'Data set
Dim Ds As New DataSet
'Llenar el Data set
Conexion.Open()
Adaptador.Fill(Ds)
Conexion.Close()
'Contar registro
If (Ds.Tables(0).Rows.Count = 0) Then
Return False
Else
a = Ds.Tables(0).Rows(0)("Nombre").ToString()
b = Ds.Tables(0).Rows(0)("Apellido").ToString()
Ds.Dispose()
Return a
Return b
Return True
End If
End Function
Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
Randomize()
Dim value As Integer = CInt(Int((20 * Rnd()) + 1))
TextBox3.Text = Buscar_Registro(value)
TextBox4.Text =
End Sub
I dont' know how to do it. The function returns only the value of "a"
Thanks
To return more values you need to change your function "as object"
Function Buscar_Registro(ByVal xId As Integer) As Object
and then you can put your return values into an object this way:
Return{a, b, true}
You'll get your values this way:
Dim mObj as object = Buscar_Registro(yourInteger)
you'll have:
a in mObj(0)
b in mObj(1)
True in mObj(2)
adapt it to your needs
EDIT (message to those that downvoted):
Creating a class an using a specific Object (the one created) to make a Function able to return multiple elements is surely the best choice.
Anyway, if someone doesn't know that it's possible to use the method that I showed in my answer, he is probably not (yet) able to create a class. So I think it's better give an usable (but not perfect) answer instead of a perfect (but unusable for the one who asked) answer.
This is what I think. Anyone can think differently.
Your best option here is to create your own class with the data you need and return that.
Public Class Data
Public Property Nombre As String
Public Property Apellido As String
End Class
And then do:
Function Buscar_Registro(ByVal xId As Integer) As Data
....
If (Ds.Tables(0).Rows.Count = 0) Then
Return Nothing
Else
a = Ds.Tables(0).Rows(0)("Nombre").ToString()
b = Ds.Tables(0).Rows(0)("Apellido").ToString()
Ds.Dispose()
return new Data() With {.Nombre = a, .Apellido = b}
End If
End Function
As of VB 15 you can use ValueTuple
Function Buscar_Registro(ByVal xId As Integer) As (Nombre As String, Apellido As String)
....
If (Ds.Tables(0).Rows.Count = 0) Then
Return (Nothing, Nothing)
Else
a = Ds.Tables(0).Rows(0)("Nombre").ToString()
b = Ds.Tables(0).Rows(0)("Apellido").ToString()
Ds.Dispose()
Return (a, b)
End If
End Function
I'm new to .net but wouldn't "ByRef" be the easiest way?
Function Buscar_Registro(ByVal xId As Integer, ByRef a As String, ByRef b As String)

Use .Contains() to match on a property of a property of <T> in LINQ query

Looking for help on how to perform a LINQ query using the .Contains() method of a List(Of T) to get back elements that are not contained in a second List(Of T) based on a property of a property of T in the first List(Of T).
Here is some sample code that I wrote up, this scenario is ficticious, but the concept is still there.
Module Module1
Sub Main()
' Get all Files in a directory that contain `.mp` in the name
Dim AllFiles As List(Of IO.FileInfo) = New IO.DirectoryInfo("C:\Test\Path").GetFiles("*.mp*").ToList
Dim ValidFiles As New List(Of fileStruct)
' Get all Files that actually have an extension of `.mp3`
AllFiles.ForEach(Sub(x) If x.Extension.Contains("mp3") Then ValidFiles.Add(New fileStruct(prop1:=x.Name, path:=x.FullName)))
' Attempting the get all files that are not listed in the Valid files list
Dim InvalidFiles As IO.FileInfo() = From file As IO.FileInfo In AllFiles Where Not ValidFiles.Contains(Function(x As fileStruct) x.fleInfo.FullName = file.FullName) Select file
' Errors on the `.Contains()` method because I have no idea what I'm doing and I am basically guessing at this point
'Here is the same but instead using the `.Any()` Method
Dim InvalidFiles As IO.FileInfo() = From file As IO.FileInfo In AllFiles Where Not ValidFiles.Any(Function(x As fileStruct) x.fleInfo.FullName = file.FullName) Select file
' This doesn't error out, but all files are returned
End Sub
Public Structure fileStruct
Private _filePath As String
Private _property1 As String
Public ReadOnly Property property1 As String
Get
Return _property1
End Get
End Property
Public ReadOnly Property fleInfo As IO.FileInfo
Get
Return New IO.FileInfo(_filePath)
End Get
End Property
Public Sub New(ByVal prop1 As String, ByVal path As String)
_property1 = prop1
_filePath = path
End Sub
End Structure
End Module
This is a more or less direct implementation of the MP3 files list in the question. I did use a FileItem class instead of a structure. The good part is afterwards:
' note: EnumerateFiles
Dim AllFiles As List(Of IO.FileInfo) = New IO.DirectoryInfo("M:\Music").
EnumerateFiles("*.mp*", IO.SearchOption.AllDirectories).ToList()
Dim goofyFilter As String() = {"g", "h", "s", "a"}
' filter All files to those starting with the above (lots of
' Aerosmith, Steely Dan and Heart)
Dim ValidFiles As List(Of FileItem) = AllFiles.
Where(Function(w) goofyFilter.Contains((w.Name.ToLower)(0))).
Select(Function(s) New FileItem(s.FullName)).ToList()
Dim invalid As List(Of FileInfo)
invalid = AllFiles.Where(Function(w) Not ValidFiles.
Any(Function(a) w.FullName = a.FilePath)).ToList()
This is much the same as Sam's answer except with your file/mp3 usage. AllFiles has 809 items, ValidFiles has 274. The resulting invalid list is 535.
Now, lets speed it up 50-60x:
Same starting code for AllFiles and ValidFiles:
Dim FileItemValid = Function(s As String)
Dim valid As Boolean = False
For Each fi As FileItem In ValidFiles
If fi.FilePath = s Then
valid = True
Exit For
End If
Next
Return valid
End Function
invalid = AllFiles.Where(Function(w) FileItemValid(w.FullName) = False).ToList()
With a Stopwatch, the results are:
Where/Any count: 535, time: 572ms
FileItemValid count: 535, time: 9ms
You get similar results with a plain old For/Each loop that calls an IsValid function.
If you do not need other FileInfo, you could create your AllFiles as a list of the same structure as you are receiving so you can do property vs property compares, use Except and Contains:
AllFiles2 = Directory.EnumerateFiles("M:\Music", "*.mp3", IO.SearchOption.AllDirectories).
Select(Function(s) New FileItem(s)).ToList()
Now you can use Contains with middling results:
invalid2 = AllFiles2.Where(Function(w) Not ValidFiles.Contains(w)).ToList()
This also allows you to use Except which is simpler and faster:
invalid2 = AllFiles2.Except(ValidFiles).ToList()
Where/Contains count: 535, time: 74ms
Except count: 535, time: 3ms
Even if you need other items from FileInfo, you can easily fetch them given the filename
As others have noted, .Except() is a better approach but here is an answer to your question:
List<int> list1 = new List<int> { 1, 2, 3 };
List<int> list2 = new List<int> { 3, 4, 5 };
List<int> list3 = list1.Where(list1value => !list2.Contains(list1value)).ToList(); // 1, 2
Based on comments here as an example using different types. This query use .Any()
List<Product> list1 = new List<Produc> { ... };
List<Vendor> list2 = new List<Vendor> { ... };
List<Product> list3 = list1.Where(product => !list2.Any(vendor => product.VendorID == vendor.ID)).ToList();
// list3 will contain products with a vendorID that does not match the ID of any vendor in list2.
Simply use Except as CraigW suggested. You have to do some projections (select) to get it done.
Dim InvalidFiles as IO.FileInfo() = AllFiles.Select(Function(p) p.FullName).Except(ValidFiles.Select(Function(x) x.fleInfo.FullName)).Select(Function(fullName) New IO.FileInfo(fullName)).ToArray()
Note: This code is not really efficient and also not very readable but works.
But i would go for something like this:
Dim AllFiles As List(Of IO.FileInfo) = New IO.DirectoryInfo("C:\MyFiles").GetFiles("*.mp*").ToList
Dim ValidFiles As New List(Of fileStruct)
Dim InvalidFiles as New List(Of FileInfo)
For Each fileInfo As FileInfo In AllFiles
If fileInfo.Extension.Contains("mp3") Then
ValidFiles.Add(New fileStruct(prop1:=fileInfo.Name, path:=fileInfo.FullName))
Else
InvalidFiles.Add(fileInfo)
End If
Next
Simple, fast and readable.

Linq always return last record

I successfully get the list of the record but the problem is the last record always override the first record. The record count already correct. Here are my codes. Please help. Thanks.
Private Function MyFunction(ByVal myList As List(Of TT_GENERAL_CONFIGURATION))
Dim pConfig As New Config
Dim lst As New List(Of Config)
For Each MyCls As TT_GENERAL_CONFIGURATION In myList
pConfig.ConfigID = MyCls.INTERNAL_NUM
pConfig.ConfigType = MyCls.CONFIG_TYPE
pConfig.ConfigName = MyCls.CONFIG_NAME
pConfig.ConfigValue = MyCls.CONFIG_VALUE
lst.Add(pConfig)
Next
Return lst
End Function
Currently you create single config instance and add it many times to your list. On each loop you only modify values of this single config object. Move config creation inside the loop:
Private Function MyFunction(ByVal myList As List(Of TT_GENERAL_CONFIGURATION))
Dim lst As New List(Of Config)
For Each MyCls As TT_GENERAL_CONFIGURATION In myList
Dim pConfig As New Config
pConfig.ConfigID = MyCls.INTERNAL_NUM
pConfig.ConfigType = MyCls.CONFIG_TYPE
pConfig.ConfigName = MyCls.CONFIG_NAME
pConfig.ConfigValue = MyCls.CONFIG_VALUE
lst.Add(pConfig)
Next
Return lst
End Function
That's because you're reusing the same reference to an object which means you're not actually adding new objects but rather new references to the same object. Your code should look like the following (the initialization of "Config" type is moved inside the loop):
Private Function MyFunction(ByVal myList As List(Of TT_GENERAL_CONFIGURATION))
Dim pConfig As Config
Dim lst As New List(Of Config)
For Each MyCls As TT_GENERAL_CONFIGURATION In myList
pConfig = New Config()
pConfig.ConfigID = MyCls.INTERNAL_NUM
pConfig.ConfigType = MyCls.CONFIG_TYPE
pConfig.ConfigName = MyCls.CONFIG_NAME
pConfig.ConfigValue = MyCls.CONFIG_VALUE
lst.Add(pConfig)
Next
Return lst
End Function
Hope this helps.
you are instanciating pConfig only one time, and then in you loop you are modifying it over and over again move the instanciation eithin the loop.

Getting an invalid cast exception when trying to order a list of objects with linq

I'm trying to sort a list of tweets (class: SimpleTweet), which each have ID associated with them (x.ID where x is an object of class SimpleTweet). I'm using linq to sort this, using "OrderByDescending", but am getting an error on the line where I set a new object of type List(Of SimpleTweet) equal to the sorted list. The error I am getting is, "System.InvalidCastException: Unable to cast object of type 'System.Linq.OrderedEnumerable2[SimpleTweet,System.Int64]' to type 'System.Collections.Generic.List1[SimpleTweet]'".
The code:
<WebMethod()> _
Public Function GetTweetsByUserID(ByVal userID As Integer) As List(Of SimpleTweet)
Dim result As New List(Of SimpleTweet)
Dim urlTwitter As String = "https://api.twitter.com/1/statuses/user_timeline.xml?include_entities=true&include_rts=true&screen_name={0}&count=3"
'Dim twitterfeed As String = utils.GetUserTwitterFeeds(userID, "docphin")
Dim lq As New lqDFDataContext
Dim var = lq.web_GetTweetsByUserID(userID).ToList()
Dim sortedresult As New List(Of SimpleTweet)
If Not var Is Nothing Then
For Each twitterfeed In var
Dim listURL As String = String.Format(urlTwitter, twitterFeed.TweeterFeed)
Dim tweetXML As XmlDocument = utils.GetXMLForURL(listURL)
Dim tweetnodelist As XmlNodeList = tweetXML.ChildNodes(1).ChildNodes
For Each node As XmlNode In tweetnodelist
Dim tweet As New SimpleTweet
tweet.CreatedAt = node.SelectSingleNode("created_at").InnerText
tweet.HTMLText = utils.ReturnTextWithHRefLink(node.SelectSingleNode("text").InnerText)
tweet.ID = node.SelectSingleNode("id").InnerText
tweet.Name = node.SelectSingleNode("user/name").InnerText
tweet.ScreenName = node.SelectSingleNode("user/screen_name").InnerText
tweet.Text = node.SelectSingleNode("text").InnerText
tweet.UserID = node.SelectSingleNode("user/id").InnerText
tweet.ProfileImageURL = node.SelectSingleNode("user/profile_image_url_https").InnerText
result.Add(tweet)
Next
Next
sortedresult = result.OrderByDescending(Function(tweet) tweet.ID)
End If
Return sortedresult
End Function
You need to materialize the result with a call to .ToList(). Add it to the end of this line:
sortedresult = result.OrderByDescending(Function(tweet) tweet.ID)
sortedResult is of type List(Of SimpleTweet) and OrderByDescending returns an IOrderedEnumerable(Of SimpleTweet) that cannot automatically be cast to the expected type.
Since you want to return a List(Of SimpleTweet) you need to call ToList to create a new list from the IEnumerable(Of SimpleTweet):
Return sortedresult.ToList()
ToList forces an immediate query evaluation.