Linq is erroring for Range variable 'Username' hides a variable - linq

First the code:
Dim tCards = (From r In myDB.CAH_TableCards Join c In myDB.CAH_Cards On r.CardId Equals c.CardId Where r.GameId = oGame.GameId And r.Round = oGame.Round Select c).SingleOrDefault
Dim pCards = From r In myDB.CAH_PlayerCards Join c In myDB.CAH_Cards On r.CardID Equals c.CardId Where r.GameId = oGame.GameId And r.username = UserName Select c
Dim rcards As List(Of TableCard) = From z In myDB.CAH_RoundCards Join c In myDB.CAH_Cards On z.CardId Equals c.CardId Where z.GameId = oGame.GameId And z.Round = oGame.Round Select c.CardId, c.CardType, c.Text, c.Answers, c.SetId, c.Added, z.Username, z.Visible
Now the class:
Imports Microsoft.VisualBasic
Public Class TableCard
Public CardId As Integer
Public CardType As Integer
Public Text As String
Public Answers As Integer
Public SetId As Integer
Public Added As Date
Public Visible As Boolean
Public Username As String
End Class
Lastly this issue:
the official error is
BC30978: Range variable 'Username' hides a variable in an enclosing block or a range variable previously defined in the query expression.
Upon researching the error I have came up with zip, zilch, nada. now the error didn't occur until I added the z.username to the very end. prior to that it worked fine. the Username field is a valid field in that table. I have used CAH_RoundCards in other parts of the code with no issue. What do I need to do to get this to work?

I figured it out...earlier in the code, i had a varible called UserName...so i just changed that and it worked.

Related

Filter generic list (comma separated values)

I want to filter list as below. I have a class & I want to filter values from that are in my filter string. I have achieved my result by a for loop but need a way without for loop.
Public Class WorkStationDetails<br><br>
Property CountryId As Integer<br>
Property CountryName As String<br>
Property TotalWrkStn As Integer<br>
Property ExistingWrkStn As Integer<br>
Property RemainingWrkStn As Integer<br><br>
End Class
Dim WrkStnDtl As List(Of WorkStationDetails)
Dim FilterWrkStnDtl As List(Of WorkStationDetails)
Dim Numbers As String()
Numbers = "1,5,6,2,9".Split(",")
For i As Integer = 0 To Numbers.Length - 1
FilterWrkStnDtl.AddRange(WrkStnDtl.FindAll(Function(p) (p.CountryId = Numbers(i))))
Next
Note: I want to achieve it like subquery in sql server.
I think you want something like this"
var numbers = "1,5,6,2,9".Split(',');
var selected = WrkStnDtl.Where(w => numbers.Contains(w.CountryId)).ToList();

differences in LINQ queries

Can someone explain why, when a query should be returning one string item only like in the example below;
From c in context.Products Where c.Id=prodId Select c.Name
Why cant that be done like so;
Dim prodDeleted as String = (From c in context.Products Where c.Id=prodId Select c.Name).ToString()
bvecause it returns this (System.Data.Objects.ObjectQuery`1[System.String]) , instead of the product name
versus having to do it like so;
Dim prodDeleted = (From c In ctx.products
Where c.Id = prodId
Select c).FirstOrDefault()
Dim deletedprodname As String = prodDeleted.Name.ToString()
Because all calls to Select return an IEnumerable rather than a single element.
To verify that your query really returns a single element, you need to add the call to Single. Or, if you don't care if a single element or multiple elements were returned, you can grab the first using First.
If you're not against using the VB.NET equivalent of lambda syntax, you can streamline everything:
Dim deletedProdName As String =
ctx.products.SingleOrDefault(Function(c) c.Id = prodId).Name

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

Unable to cast object

I am new to LINQ, I tried to run the following code and I got InvalidCastException error: "Unable to cast object of type 'd__3a`1[debug.Product]' to type 'debug.Product'" - what is wrong?
Code (VB - using VS2008)
Private Sub btnLinq_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLinq.Click
Dim Products As New List(Of Product)
Dim p1 As New Product
p1._ID = "1"
p1._Name = "Product A"
Products.Add(p1)
Dim p2 As New Product
p2._ID = "2"
p2._Name = "Product B"
Products.Add(p2)
Dim p3 As New Product
p3._ID = "3"
p3._Name = "Product C"
Products.Add(p3)
Dim prod As Product = From p In Products Where p._ID = "1" Select p Take 1
MsgBox(prod._ID)
End Sub
End Class
Public Class Product
Public _ID As String
Public _Name As String
End Class
Take returns an IEnumerable<Product> (in your case), and not a Product.
(Check it by outputting result.GetType() ):
(note that my example code is in C#)
List<Product> products = new List<Product> ();
products.Add (new Product ()
{
Id = 1,
Name = "Prod1"
});
products.Add (new Product ()
{
Id = 2,
Name = "Prod2"
});
var result = ( from p in products
where p.Id == 1
select p ).Take (1);
Console.WriteLine (result.GetType ());
Console.ReadLine ();
In my case, the code above outputs:
System.Linq.Enumerable+<TakeIterator>d__3a`1[LinqTest.Product]
In your case, instead of using Take 1, you could try to use First or FirstOrDefault instead.
So, try this:
var result = ( from p in products
where p.Id == 1
select p ).FirstOrDefault ();
Console.WriteLine (result.GetType ());
Console.WriteLine (result.Name);
The Take method (Enumerable.Take) doesn't return an element, rather it returns an another sequence (IEnumerable<Product>). Take(n) just creates a new sequence with a maximum of n elements.
To take the first element from the sequence use one of the following methods:
FirstOrDefault() - returns null if the sequence is empty
First() - throws InvalidOperationException if the sequence is empty

What is the correct way of reading single line of data by using Linq to SQL?

I'm very new to Linq, I can find multi-line data reading examples everywhere (by using foreach()), but what is the correct way of reading a single line of data? Like a classic Product Detail page.
Below is what I tried:
var q = from c in db.Products
where c.ProductId == ProductId
select new { c.ProductName, c.ProductDescription, c.ProductPrice, c.ProductDate };
string strProductName = q.First().ProductName.ToString();
string strProductDescription = q.First().ProductDescription.ToString();
string strProductPrice = q.First().ProductPrice.ToString();
string strProductDate = q.First().ProductDate.ToString();
The code looks good to me, but when I see the actual SQL expressions generated by using SQL Profiler, it makes me scared! The program executed four Sql expressions and they are exactly the same!
Because I'm reading four columns from a single line. I think I must did something wrong, so I was wondering what is the right way of doing this?
Thanks!
Using the First() extension method would throw the System.InvalidOperationException when no element in a sequence satisfies a specified condition.
If you use the FirstOrDefault() extension method, you can test against the returned object to see if it's null or not.
FirstOrDefault returns the first element of a sequence, or a default value if the sequence contains no elements; in this case the default value of a Product should be null. Attempting to access the properties on this null object will throw ArgumentNullException
var q = (from c in db.Products
where c.ProductId == ProductId
select new { c.ProductName, c.ProductDescription, c.ProductPrice, c.ProductDate }).FirstOrDefault();
if (q != null)
{
string strProductName = q.ProductName;
string strProductDescription = q.ProductDescription;
string strProductPrice = q.ProductPrice;
string strProductDate = q.ProductDate;
}
Also, you shouldn't have to cast each Property ToString() if you're object model is setup correctly. ProductName, ProductDescription, etc.. should already be a string.
The reason you're getting 4 separate sql queries, is because each time you call q.First().<PropertyHere> linq is generating a new Query.
var q = (from c in db.Products
where c.ProductId == ProductId
select new { c.ProductName, c.ProductDescription, c.ProductPrice, c.ProductDate }
).First ();
string strProductName = q.ProductName.ToString();
string strProductDescription = q.ProductDescription.ToString();
string strProductPrice = q.ProductPrice.ToString();
string strProductDate = q.ProductDate.ToString();

Resources