LINQ to SQL, Visual Basic - Listbox Receives the Query NOT the Result - visual-studio-2010

Overview
This is a homework assignment using LINQ to SQL in a Visual Basic application. It is correct in most ways except that I have a partially broken result. Rather than adding the result of my second query to my listbox, my code adds a weird representation of the query itself. Below is a description of the DB, followed by my output (intended and actual), and finally my code. Please point me toward the broken concept so I can figure out what I am missing. Thanks much.
DB info
I am using two tables, called Members and Payments, from one DB. Members has a primary key called ID and also has the fields first_name and last_name. Payments has a foreign key called Members_Id, which is associated to the Member's primary key; Payments also has the payment values under the column Payments.
Output should be like this
Member name = John Smith
$48.00, 10/20/2005
$44.00, 3/11/2006
But is this instead
Member name = SELECT ([t0].[First_Name] + #p1) + [t0].[Last_Name]
AS [value]FROM[dbo].[Members] AS [t0].[ID] = #p0
$48.00, 10/20/2005
$44.00, 3/11/2006
My VB Code
Public Class FormPaymentsGroup
Private db As New KarateClassesDataContext
Private Sub FormPaymentsGroup_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Me.PaymentsTableAdapter.Fill(Me.KarateDataSet.Payments)
'Group payments by Member_ID (FKey) in the Payments table. (Working fine)
Dim IdQuery = From aMember In db.Payments
Group aMember By aMember.Member_Id
Into MemberPayments = Group
For Each memberID In IdQuery
' Use the passed member_Id to target the row in the Members table and return the first_name & last_name.
' PROBLEM: This only seems to be returning the query itself; not the result.
Dim currMemberID = memberID.Member_Id
Dim nameQuery = From aName In db.Members
Where aName.ID = currMemberID
Select aName.First_Name + " " + aName.Last_Name
Dim currName = nameQuery.ToString ' Load the query result into a portable variable.
LbxMemberPayments.Items.Add("Member name = " & currName) ' PROBLEM: This is where the name SHOULD BE posted to the listbox.
' This is bound to the Members table but directs it based on the above IdQuery.
For Each enteredPayment In memberID.MemberPayments
LbxMemberPayments.Items.Add(vbTab & FormatCurrency(enteredPayment.Amount) & ", " & enteredPayment.Payment_Date)
Next
LbxMemberPayments.Items.Add(vbCr) ' Carriage return formatting
Next
End Sub
End Class

change
Dim currName = nameQuery.ToString
to
Dim currName = nameQuery.FirstOrDefault

Related

Retrieving Only Selected Field Using LINQ

i have a problems regarding on filtering my code in retrieving companyName from its table..when i query here is the result .. please see my code
Sub call_customers(ByVal dgv_customers As DataGridView)
Dim customers_name = From cust In dbcon.Customers _
Select cust.CustomerID, cust.CompanyName Order By CompanyName Ascending
dgv_customers.DataSource = customers_name
End Sub
the display is CustomerID and CompanyName.. yeah its true.. no problem with the code..
and if i only select cust.companyname the result is this ....like this code
Sub call_customers(ByVal dgv_customers As DataGridView)
Dim customers_name = From cust In dbcon.Customers _
Select cust.CompanyName
dgv_customers.DataSource = customers_name
End Sub
the output is this...
enter image description here
no display and it says length.. why? newbie in LINQ sir ..
please help..
Originally, you were giving the grid an object, and it was displaying each of the properties of that object.
Now that you are giving it a string, it is doing the same thing, but now, the only property on the string is the length,

Display newly created record in Formview

I have this form on VS2012 with asp.net. First I do search for the patron, then go to verify information for that patron. This patron information is displayed in ItemTemplate(ReadOnly). If that is not the patron they are looking for then they can add a new patron with "New button" (asp.net code). I am able to get the id of the new Patron(which is PK). However I am not able to display this newly created record on the form after inserting. It still displays the record which was on display. Since this a formview I did not enable "Paging".
Is it possible to call the pageload event from datasource_inserted event? Then I can pass the new patron ID for display. I declared this ID as global variable?
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim lvPatronID As String
lvPatronID = Request.QueryString("value1")
If lvPatronID = "" Then
frmPatronView.ChangeMode(FormViewMode.Insert)
Else
frmPatronView.ChangeMode(FormViewMode.ReadOnly)
GvPatronID = lvPatronID
lblPatronID.Text = GvPatronID
End If
Protected Sub PatronDS_Inserted(sender As Object, e As SqlDataSourceStatusEventArgs) Handles PatronDS.Inserted
NewID = e.Command.Parameters("#PatronID").Value.ToString
GvPatronID = NewID
End Sub
Well I answered part of my own question. The following change to the Inserted event will let me view the newly inserted data. I have another button to add new record in the emptytemplate of the search form. This is why I am changing the mode to insert as the default mode is readonly. This will let me insert the data but after inserting it doesn't display the form at all. Not sure why Inserted event is not kicking in properly.
Protected Sub PatronDS_Inserted(sender As Object, e As SqlDataSourceStatusEventArgs) Handles PatronDS.Inserted
Dim NewID As String = Nothing
Try
NewID = e.Command.Parameters("#PatronID").Value.ToString
PatronDS.SelectCommand = "SELECT * FROM tblPatron WHERE PatronID='" & NewID & "'"
lblPatronID.Text = NewID.Trim()
frmPatronView.DataBind()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub

deleting a record in linq to sql (vb.net) what is wrong with my code?

I am getting the correct Employee Id in the VarEmpID variable. When I click on delete
It is giving me
Unable to cast object of type 'System.Data.Linq.DataQuery`1[my name space]' to type 'namespace'.
enter code here
Protected Sub radGrid1_DeleteCommand(ByVal source As Object, ByVal e As GridCommandEventArgs) Handles radGrid1.DeleteCommand
Dim VarEmpId As String = (CType(e.Item, GridDataItem)).OwnerTableView.DataKeyValues(e.Item.ItemIndex)("EmpId").ToString()
Using dc1 As New EmployeesDataClassesDataContext()
Dim EmployeeEntry = (From p In dc1.Employees
Where (p.EmpId = VarEmpId)
Select p)
dc1.Employees.DeleteOnSubmit(EmployeeEntry)
dc1.SubmitChanges()
Dim queryResults = (From queryItem In EmployeeEntry Select queryItem).ToList()
If queryResults.Any Then
radGrid1.DataSource = queryResults
radGrid1.DataBind()
End If
End Using
End Sub
dc1.Employees.DeleteOnSubmit(EmployeeEntry)
That method expects an Employee instance. Instead, you passed in an employee query.
Dim EmployeeEntry = ( query )
This is a query, not an entry. Consider calling Enumerable.First to get the first result of the query, and then deleting that.
Modified added Dim EmployeeEntry = (From p In dc1.Employees Where (p.EmpId = VarEmpId) Select p).singleorDefault() After that commented out the queryresults part and binded data again it solved my problem. – SmilingLily

VBA : Querying Access with Excel on server

I'm working with Excel project wich helps to calculate the price of any peace of furniture. The first task is to pick all the materials from the database.
This is the code:
Sub Material_search()
Dim cnt As New ADODB.connection
Dim rst As New ADODB.Recordset
Dim rcArray As Variant
Dim sSQL As String
Dim db_path As String, db_conn As String
Dim item As String
item = Replace(TextBox1.Text, " ", "%") ' Search word
sSQL = "Select Data, NomNr, Preke, Matas, Kaina, Tiek from VazPirkPrekes " & _
"Where VazPirkPrekes.PirkVazID IN (SELECT VazPirkimo.PirkVazID FROM VazPirkimo Where VazPirkimo.Sandelys like '%ALIAVOS')" & _
" and Year(VazPirkPrekes.Data)>=2011 and Preke Like '%" + item + "%' and Kaina > 0" & _
" Order by Preke, Data Desc"
db_path = Sheets("TMP").Range("B6").value
db_conn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & db_path & ";"
cnt.Open db_conn
rst.Open sSQL, cnt, adOpenForwardOnly, adLockReadOnly
ListBox1.Clear
If Not rst.EOF Then
rcArray = (rst.GetRows)
rcArray = WorksheetFunction.Transpose(rcArray)
Dim a As Variant
With ListBox1
.ColumnCount = 6
.list = rcArray
.ListIndex = -1
End With
End If
rst.Close: Set rst = Nothing
cnt.Close: Set cnt = Nothing
Label4.Caption = UBound(ListBox1.list) + 1
End Sub
recently I came up with some trouble while querying Access mdb file. The problem is when database file is on local disk, the search works very fast, but when i put database file on server, the search takes 10 times longer, which is not acceptable.
Is there any optimisation for this code ? or is it a server problem
Thanks in advance
That query requires Access' database engine retrieve all 190K rows from both tables. It's not surprising it is slow, and the slowness is compounded when the db engine must retrieve 2 * 190K rows across the network.
If TextBox1.Text contains "foo", this is the statement you're asking the db engine to run:
Select Data, NomNr, Preke, Matas, Kaina, Tiek
from VazPirkPrekes
Where
VazPirkPrekes.PirkVazID IN (
SELECT VazPirkimo.PirkVazID
FROM VazPirkimo
Where VazPirkimo.Sandelys like '%ALIAVOS')
and Year(VazPirkPrekes.Data)>=2011
and Preke Like '%foo%'
and Kaina > 0
Order by Preke, Data Desc
The engine must retrieve all 190K rows from the VazPirkimo table before it can determine which of them include Sandelys values which end with "ALIAVOS". If your selection criterion was for values which start with "ALIAVOS", the engine could use an index on Sandelys to limit the number of rows it must retrieve from VazPirkimo. However, since that approach is probably not an option for you, consider adding a numeric field, Sandelys_group, to VazPirkimo and create an index on Sandelys_group. Give all rows where Sandelys ends with "ALIAVOS" the same Sandelys_group number (1). Then your "IN ()" condition could be this:
SELECT VazPirkimo.PirkVazID
FROM VazPirkimo
Where VazPirkimo.Sandelys_group = 1
The index on Sandelys_group will allow the db engine to retrieve only the matching rows, which will hopefully be a small subset of the 190K rows in the table.
There are other changes you can make to speed up your query. Look at this criterion from your WHERE clause:
Year(VazPirkPrekes.Data)>=2011
That forces the db engine to retrieve all 190K rows from VazPirkPrekes before it can determine which of them are from 2011. With an index on Data, this should be much faster:
VazPirkPrekes.Data >= #2011-01-01# AND VazPirkPrekes.Data < #2012-01-01#
This WHERE criterion will be faster with an index on Kaina:
Kaina > 0
Your ORDER BY begs for indexes on Preke and Data.
Order by Preke, Data Desc
Any or all of those changes could help speed up the query, though I don't know by how much. The killer is this WHERE criterion:
Preke Like '%foo%'
The issue here is similar to the problem with the "Sandelys like" comparison. Since this asks for the rows where Preke contains "foo", rather than starts with "foo", the db engine can't take advantage of an index on Preke to retrieve only the matching rows. It must retrieve all 190K VazPirkPrekes rows to figure out which match. Unless you can use a different criterion for this one, you will be limited as to how much you can speed up the query.
Thanks for the optimization tips, but as I said the problem occurs only when I put data base file on server. And there is not much help from optimization. But I thought about other idea.
The search of empty blank "" returns about 40k records (these records covers everything I need) . So I'm going to put all these records on a distinct sheet on workbook_activate event and later do the query only in that sheet.
Sub Database_upload()
Application.DisplayAlerts = False
On Error Resume Next
Sheets("DATA_BASE").Delete
On Error GoTo 0
Application.DisplayAlerts = False
Sheets.Add
ActiveSheet.name = "DATA_BASE"
Sheets("DATA_BASE").Visible = False: Sheets("DARBALAUKIS").activate
Dim cnt As New ADODB.connection
Dim rcArray As Variant
Dim sSQL As String
Dim db_path As String, db_conn As String
Dim item As String
Dim qQt As QueryTable
item = "" 'search for empty blanks
sSQL = "Select Data, NomNr, Preke, Matas, Kaina, Tiek from VazPirkPrekes " & _
"Where VazPirkPrekes.PirkVazID IN (SELECT VazPirkimo.PirkVazID FROM VazPirkimo Where VazPirkimo.Sandelys like '%ALIAVOS')" & _
" and Year(VazPirkPrekes.Data)>=2011 and Preke Like '%" + item + "%' and Kaina > 0" & _
" Order by Preke, Data Desc"
db_path = Sheets("TMP").Range("B6").value
db_conn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & db_path & ";"
db_conn = "ODBC;DSN=MS Access 97 Database;"
db_conn = db_conn & "DBQ=" & db_path
Set qQt = Sheets("Sheet1").QueryTables.Add(connection:=db_conn, Destination:=Sheets("Sheet1").Range("A1"), Sql:=sSQL)
qQt.Refresh BackgroundQuery:=False
End Sub
Results:
Program takes longer on startup, but the search time is acceptable - for me the problem is solved :)

Linq Compiled Queries and int[] as parameter

I'm using the following LINQ to SQL compiled query.
private static Func<MyDataContext, int[], int> MainSearchQuery =
CompiledQuery.Compile((MyDataContext db, int[] online ) =>
(from u in db.Users where online.Contains(u.username)
select u));
I know it is not possible to use sequence input paramter for a compiled query and im getting “Parameters cannot be sequences” error when running it.
On another post here related , I saw that there is some solution but I couldn't understand it.
Does anyone know to use complied query with array as input paramter?
Please post example if you do.
Like the post that you referenced, it's not really possible out of the box. The post also references creating your own query provider, but it's a bit of overhead and complexity that you probably don't need.
You have a few options here:
Don't use a compiled query. Rather, have a method which will create a where clause from each item in the array resulting in something like this (psuedo-code):
where
online[0] == u.username ||
online[1] == u.username ||
...
online[n] == u.username
Note that you would have to use expression here to create each OR clause.
If you are using SQL Server 2008, create a scalar valued function which will take a table-valued parameter and a value to compare againt. It will return a bit (to indicate if the item is in the values in the table). Then expose that function through LINQ-to-SQL on your data context. From there, you should be able to create a CompiledQuery for that. Note that in this case, you should take an IEnumerable<string> (assuming username is of type string) instead of an array, just because you might have more than one way of representing a sequence of strings, and to SQL server for this operation, it won't matter what the order is.
One solution that I have found myself doing (for MS SQL 2005/2008). And I'm not sure if it is appropriate in all scenarios is to just write dynamic sql and execute it against the datacontext using the ExecuteQuery method.
For example, if I have an unbounded list that I am trying to pass to a query to do a contains...
' Mock a list of values
Dim ids as New List(of Integer)
ids.Add(1)
ids.Add(2)
' ....
ids.Add(1234)
Dim indivs = (From c In context.Individuals _
Where ids.Contains(c.Id) _
Select c).ToList
I would modify this query to create a SQL string to execute against the database directly like so...
Dim str As New Text.StringBuilder("")
Dim declareStmt as string = "declare #ids table (indivId int) " & vbcrlf)
For i As Integer = 0 To ids.Count - 1
str.Append("select " & ids(i).ToString() & " & vbcrlf)
If i < ids.Count Then
str.Append("union " & vbcrlf)
End If
Next
Dim selStatement As String = "select * From " & context.Mapping.GetTable(GetType(Individuals)).TableName & _
" indiv " & vbcrlf & _
" inner join #ids ids on indiv.id = ids.id"
Dim query = declareStmt & str.ToString & selStatement
Dim result = context.ExecuteQuery(of Individual)(query).ToList
So barring any syntax errors or bugs that I coded (the above is more or less psuedo code and not tested), the above will generate a table variable in SQL and execute an inner join against the desired table (Individuals in this example) and avoid the use of a "IN" statement.
Hope that helps someone out!

Resources