LINQ VB.NET variable not found when looping through grouped query - vb.net

I'm trying to do the following LINQ grouping, which works in the debugger (the results are populated in the GroupedOrders object. But VS 2008 gives me the following error at design time...
Name 'x' is not declared
Dim GroupedOrders = (From m In thisConsultant.orders _
Group m By Key = m.commCode Into Group _
Select commCode = Key, orders = Group)
For Each x In GroupedOrders
Next
Public Structure consultantDetail
Public orders As List(Of orderDetail)
End Structure
Public Structure orderDetail
Public transactionID As Integer
Public qualifyingVolume As Decimal
Public commissionableVolume As Decimal
Public sponsorID As Integer
Public orderDate As DateTime
Public commCode As String
Public commPercentage As Decimal
Public discountPercent As Decimal
End Structure

Do you have Option Infer On?

My guess is that you have Option Strict On and Option Infer Off. To check these settings:
Right-click on your project in the solution explorer
Select Properties
Select the Compile tab on the left

try to surround the Linq query with try-catch. Sometimes, there are error that are not catch directly by VS2008.

Related

Check if ArrayList contains an object with a property that equals a specific value

So I have an application in VB.net that is pulling data from a table and inserting it into an arraylist to be used later. What I want to do is before adding the object to the arraylist, I want to check that arraylist to see if the object exists, but I want to be able to check based off a particular property of that object.
Here is an example of what I am talking about:
Lets say Im pulling info from a table with the following columns:
InvoiceNo|DateCharged|Quantity|TotalCharge
I have a SQL statement that pulls info from a table and then I use a data reader to go through the info. My Code looks somewhat like this:
Dim dbobjM As New clsDbobjManual()
If dbobjM.Exec_SQL_DR("SELECT InvoiceNo, DateCharged, Quantity, TotalCharges From Invoices") = 0 Then
If dbobjM.DataReader.HasRows Then
Dim invoicelist As New ArrayList(5000)
Dim invoiceno As String = String.Empty
Do While dbobjM.DataReader.Read()
invoicelist.Add(New Invoice(dbobjM.DataReader.GetInt32(0), dbobjM.DataReader.Value(1), dbobjM.DataReader.GetInt32(2), dbobjM.DataReader.GetFloat(3)))
Loop
End If
End if
(Exec_SQL_DR is a function in the clsDbobjManual class that check to make sure the SQL is in the proper syntax first and checks that records are returned otherwise it returns an error)
Basically what I want to do is before I add a new object to the arraylist I want to check if an object already exists in the list where the InvoiceNo is a particular value, or the value pulled from the table each time to make sure there is no duplicates. I want one object in the list for each InvoiceNo.
Im looking for something like:
If Not invoicelist.Contains(Object where InvoiceNo = dbobjM.DataReader.GetInt32(0)) Then
invoicelist.Add
End If
But I cant seem to find what I need, any help is greatly appreciated
There is no need to use the outdated ArrayList: a List will serve you better. Please see ArrayList vs List<> in C# if you need reasons - the advantages for a list apply to VB.NET too.
Without seeing your clsDbobjManual or Invoice classes, I ended up writing the minimal code to do what you're after, which is basically the check for invoices.Any(Function(i) i.InvoiceNo = inv.InvoiceNo), which you can do if you have the data in a List(Of Invoice).
Please note that I assumed that the appropriate data types have been used in the database - you should use the Decimal type for money as otherwise you can end up with significant rounding errors, and a date should be stored as DateTime, not as a string.
Imports System.Data.SqlClient
Module Module1
Class Invoice
Property InvoiceNo As Integer
Property DateCharged As DateTime
Property Quantity As Integer
Property TotalCharges As Decimal
Sub New()
' empty constructor
End Sub
Sub New(invoiceNo As Integer, dateCharged As DateTime, quantity As Integer, totalCharges As Decimal)
Me.InvoiceNo = invoiceNo
Me.DateCharged = dateCharged
Me.Quantity = quantity
Me.TotalCharges = totalCharges
End Sub
End Class
Function LoadData() As List(Of Invoice)
Dim invoices As New List(Of Invoice)
Dim connStr As String = "your connection string"
Dim sql = "SELECT InvoiceNo, DateCharged, Quantity, TotalCharges From Invoices"
Using sqlConn As New SqlConnection(connStr)
Using sqlCmd As New SqlCommand(sql, sqlConn)
Dim reader As SqlDataReader = sqlCmd.ExecuteReader()
While reader.Read()
Dim inv As New Invoice(reader.GetInt32(0), reader.GetDateTime(1), reader.GetInt32(2), reader.GetDecimal(3))
If Not (invoices.Any(Function(i) i.InvoiceNo = inv.InvoiceNo)) Then
invoices.Add(inv)
Else
' there is a duplicate invoice number
End If
End While
End Using
End Using
Return invoices
End Function
Sub Main()
Dim uniqueInvoices As List(Of Invoice) = LoadData()
' uniqueInvoices now contains the data
End Sub
End Module
If you had a lot of invoice entries to go through, you would likely be better off writing an SQL query to do that.
If you actually just want to find duplicate invoice numbers, you could use the SQL
SELECT [InvoiceNo]
FROM testTable
GROUP BY [InvoiceNo]
HAVING COUNT([InvoiceNo]) > 1
Finally, please ensure that you are using Option Strict On so that you don't make accidental data type errors - they can drastically slow down your program and lead to erroneous results.
You can use linq to select the objects that matches your condition.
Dim result = (From invoiceitem As Invoice
In invoicelist
Where invoiceitem.InvoiceNo = dbobjM.DataReader.GetInt32(0)
Select invoiceitem).ToList()
If Not result.Count > 0 Then
invoicelist.Add(New Invoice(dbobjM.DataReader.GetInt32(0), dbobjM.DataReader.Value(1), dbobjM.DataReader.GetInt32(2), dbobjM.DataReader.GetFloat(3)))
End If

Handling RANK (additional column in SQL Server) while executing Full Text Search in Silverlight enabled WCF

Here is the code and applies only to Full Text Search enabled table in SQL Server. I want help in knowing if my approach is right.
Dim dbConn as ObjectContext = DirectCast(MyEntConn, IObjectContextAdapter).ObjectContext
Dim CurPrimaryKey as string = dbConn.ExecuteStoreQuery(of String)(String.Concat("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE where table_name like 'MyTable'")).ToList()(0)
Dim FTSQry = "SELECT fts.RANK, * from MyTable as tbl inner join CONTAINSTABLE(MyTable, (*), 'ISABOUT(venkatesh WEIGHT(0.9), venketash WEIGHT(0.6))' AS fts ON tbl." & CurPrimaryKey & " = fts.[KEY] ORDER BY fts.RANK DESC, " & CurPrimaryKey
Dim FTSQryOutput = dbConn.ExecuteStoreQuery(Of MyTable)(FTSQry)).ToList
This query taken during debug, executed in SSMS gives expected output along with RANK column. Great. But executed in VS will not give output as the Entity Framework generated code for MyTable does not have the [RANK] column.
So, I added a class as below in the web project (Silverlight web project).
Partial Public Class MyTable
Public Property RANK as Integer
End Class
Now the FTSQuery execution in Visual Studio happens fine. But the RANK column output is always 0 while SSMS gives correct RANK values for same query. If I change Integer to Double for RANK column output is 0.0. If I change to any other type, the column has Nothing as value.
Please help.

Using db find on something other than primary key

I have searched on the internet for the answer to this question with no luck. I have a model that exists in the database created with entity framework and is accessed via db (an instance of my DBContext class).
Function Details(id As Integer) As ViewResult
Dim bill As Bill = db.Bills.Find(id)
Return View(bill)
End Function
The model for the bill class is defined as:
Public Class Bill
Public Property BillId() As Integer
Public Property CustomerId() As String
Public Property BillStatus() As String
End Class
Assuming then that in the function mentioned first I was passed the CustomerId rather than the primary key of this model (BillId), how would I use this to create a 'Dim bill As Bill' that included only bills with that customerId.
As in the example above where Bills was filtered with .Find(id) - which only looks at the primary key - I want to be able to use a similar method to .Find() but on a non key field: CustomerId in this case.
Or if you are sure there will always only be one entity matching that CustomerId you can use Single.
VB .NET
Dim myBill = db.Bills.Single(Function(x) x.CustomerId = cId);
C# .NET
var myBill = db.Bills.Single(x => x.CustomerId == cId);
Note, this will throw an exception if exactly 1 is not found.
Use .NET's version of filter (Where)
Dim bills = db.Bills.Where(Function(x) x.CustomerId = cId)
or
Dim bills = From i in db.Bills
Where i.CustomerId = cId
Select i
EDIT: Per Scott's comment call FirstOrDefault() to return only one result. If none exist, null will be returned.
To do that.
Dim bill = (From i in db.Bills
Where i.CustomerId = cId
Select i).FirstOrDefault()
If Not IsDBNull(bill) Then
/*Do Stuff*/
End If

Compiled LINQ joins

I have got a bit of slack project time so I decided to star in a production of micro optimisation theatre. The app I’m working on is going to be run on some quite low performance tablets so I was looking for ways to speed things up. Given that I’m using LINQ to Entities I looked into precompiled queries to boast performance and so came up with this simple one to return a list of contacts for a given company
Public ReadOnly pContacts_list_query As Func(Of SpiraxDDWEntities, Integer, IQueryable(Of tblContacts)) = _
CompiledQuery.Compile(Of SpiraxDDWEntities, Integer, IQueryable(Of tblContacts))(Function(ctx As SpiraxDDWEntities, pCompany_ABN As Integer) _
From Contact_data In ctx.tblContacts Where Contact_data.AccountNumber = pCompany_ABN
)
Now that’s fine as its just one table so the IQueryable type can be the table name. My question is what if I wanted to precompile a query with joins? For example this one
Dim Quote_QRY = From Quote_data In linEntities.tblQuote
Join Quote_value_data In linEntities.tblQuoteValue On Quote_data.ID Equals Quote_value_data.QuoteID
Join Quote_status_data In linEntities.tblQuoteStatus On Quote_data.Status Equals Quote_status_data.Abbreviation
Where Quote_data.AccountNo = Me.txtCompany_ABN.Text
Select Quote_data.ID, Status = Quote_status_data.Description, Quote_data.Contact, Quote_data.Project, Quote_value_data.QuoteValue
How would I go about that?
Thanks
The join here isn't the issue. The issue is projecting into an anonymous type. In this case, you need to create a named class and project into it in your select clause:
Public Class Quote
Public Property ID As String
Public Property Status As String
Public Property Contact As String
Public Property Project As String
Public Property QuoteValue As String
End Class
Public ReadOnly Quote_query As Func(Of SpiraxDDWEntities, Integer, IQueryable(Of Quotes)) = _
CompiledQuery.Compile(Of SpiraxDDWEntities, Integer, IQueryable(Of Quotes))(Function(ctx As SpiraxDDWEntities, pCompany_ABN As Integer)
From Quote_data In linEntities.tblQuote
Join Quote_value_data In linEntities.tblQuoteValue On Quote_data.ID Equals Quote_value_data.QuoteID
Join Quote_status_data In linEntities.tblQuoteStatus On Quote_data.Status Equals Quote_status_data.Abbreviation
Where Quote_data.AccountNo = Me.txtCompany_ABN.Text
Select New Quote With {
.ID = Quote_data.ID,
.Status = Quote_status_data.Description,
.Contact = Quote_data.Contact,
.Project = Quote_data.Project,
.QuoteValue = Quote_value_data.QuoteValue
}
One additional caveat: I'm not sure off the top of my head if Compiled Query requires that the resulting type be a mapped entity type or not. If so, you may need to alter the EDMX to make EF think that the type is valid. Alternatively, you may want to consider using a Defining query in the CSDL.

first time I have to create an extension for linq2sql, how to do this one?

I have this one line property
Public ReadOnly Property DateToUniversal(ByVal dt As Nullable(Of Date)) As String
Get
Return If(dt.HasValue, dt.Value.ToString("u").Substring(0, 10), "")
End Get
End Property
if i'm trying to use that into a
from n in mydatacontext
select new myObj {n.field1,n.field2, DateToUniversal(n.field3)}
it doesn't work all the time because LINQ2SQL cannot convert that into a sql query.
is there a way to do this?
You'll have to turn it into two queries:
var query = (from n in mydatacontext select new {n.field1,n.field2, n.field3}).AsEnumerable();
query = from n in query select new {n.field1, n.field2, DateToUniversal(n.field3)};
It's important that query be IEnumerable instead of var (or IQueryable)It's important that you call AsEnumerable() so that you get back an IEnumerable<T>, as we want to force the second query to use LINQ to Objects on the results of the first (LINQ to SQL) query.
I'm not in front of VS at this time, but this should do the trick.
Thanks to itowlson for pointing out that it has to be IEnumerable<T>, not just IEnumerable!