Query not returning anything - c#

I have 2 tables: winery and wineType (in wineType I have foreign key for winery, called wineryID). I try get all winery names that produce wine like the one the client selected from drop down list. And I have this function
public void ispolniLista()
{
DataClassesDataContext MyDB = new DataClassesDataContext();
var id = from wineT in MyDB.WineTypes where wineT.kind == ddlSorti.SelectedItem.Text select new { wineT.wineryID };
List<int> listaID = id as List<int>;
List<string> listaIminja = new List<string>();
try
{
foreach (int i in listaID)
{
var vname = from w in MyDB.Wineries where w.wineryID == i select new { w.name };
listaIminja.Add(vname.ToString());
}
lstVinarii.DataSource = listaIminja;
lstVinarii.DataBind();
}
catch (NullReferenceException err)
{
Console.Write(err.Message);
}
}
And I have nothing for result, the lstVinarii is empty.

Where you are casting the result like this:
List<int> listaID = id as List<int>;
You need to instantiate it so the enumerable is actually enumerated, like this:
List<int> listaID = new List<int>(id);
However, it would be worth re-writing this to take advantage of joins, because you're going to be popping off a lot of queries with the method above (because you have a query within a loop).

List<int> id = ( from wineT in MyDB.WineTypes where wineT.kind == ddlSorti.SelectedItem.Text select wineT.wineryID ).ToList();
Do this !

EDIT
Note: From your code Remove new from select, no need to create extra anonymous type that is also one problem
To avoid comment error write like this
var id = from wineT in MyDB.WineTypes
where wineT.kind == ddlSorti.SelectedItem.Text
select wineT.wineryID ;
Remove new from select, no need to create extra anonymous type same in below code
try
List<int> listaID = id.ToList<int>();
than remove foreach loop and write like this
var listaIminja= (from win MyDB.Wineries
where listaID .Contains( w.wineryID )
select w.name ).ToList();
lstVinarii.DataSource = listaIminja;
lstVinarii.DataBind();

Related

LINQ get find all with id in list

I am trying to figure out non query way to do return a list of all objects if their ID is in test list. Example below:
Hero - table
Columns: id = INT , name = STRING, age = INT, power = INT;
var testList = {1,2,3};
var secondArray = {};
foreach (var id in testList )
{
// check if ID in database
var item = db.Hero.ToList().Find(o => o.Id = id);
if( item != null)
{
secondArray.push(item);
}
}
Now i have seen this whole thing done in single line but cannot remember how it was done.
The result i am after is List of all objects containing that have ids 1,2,3.
You have to use Contains on testList:
var secondArray= db.Hero.Where (h=> testList.Contains(h.Id))
How about
var result = db.Hero.Where(x => testList.Contains(x.Id));
This would hit DB just once instead of 3 times.

Subquery using LINQ to SQL

I am using LINQ to SQL in my C# tutorial project but I have basic knowledge of it.
I made a SQL query like this:
SELECT ID,HeroName,HeroRarity,Initiative,Attack,Attack1
FROM CharactersName
WHERE ID IN(
SELECT HeroID
FROM Hero_Group
WHERE GroupID=1
)
(Hero_Group) is a table to deal with a many-to-many relation between (CharactersName) table and another table named (Groups) where a character can be in more than one group.
I tried to write it in LINQ like this:
void FilterGroup()
{
HDAEntities db = new HDAEntities();
var query = from obj in db.CharactersNames
where obj.ID == from obj2 in db.Hero_Group
where obj2.GroupID == comboBox1.SelectedIndex
select new
{
obj2.GroupID
}
select new
{
obj.ID,
obj.HeroName,
obj.HeroRarity,
obj.Initiative,
obj.Attack,
obj.Attack1
};
}
But of course this is gibberish.
Can someone help me, please ? (be informed that I have little knowledge of LINQ to SQL)
~TIA~
You can do it like this:
void FilterGroup()
{
HDAEntities db = new HDAEntities();
var subQuery = db.Hero_Group.Where(h => h.GroupID == comboBox1.selectedIndex)
.Select(h => h.GroupID);
var query = from obj in db.CharactersNames
where subQuery.Contains(obj.ID)
select new
{
obj.ID,
obj.HeroName,
obj.HeroRarity,
obj.Initiative,
obj.Attack,
obj.Attack1
};
var result = query.ToList(); // this is where your query and subquery are evaluated and sent to the database
db.Dispose();
db = null;
}
Note that the subQuery is not evaluated until you call ToList(). You also need to dispose the object (or try the using statement to create the HDAEntities object). Also, make sure you don't dispose the db before evaluating the query (calling ToList after Dispose will throw an exception).
var query = from obj in db.CharactersNames
where (from obj2 in db.Hero_Group
where obj2.GroupID == comboBox1.SelectedIndex
select new {obj2.GroupID}).Contains(obj.ID)
select new
{
obj.ID,
obj.HeroName,
obj.HeroRarity,
obj.Initiative,
obj.Attack,
obj.Attack1
};
var query = from obj in db.CharactersNames
where (from obj2 in db.Hero_Group
where obj2.GroupID == comboBox1.SelectedIndex
select new {obj2.GroupID}).Contains(obj.ID)
select new
{
obj.ID,
obj.HeroName,
obj.HeroRarity,
obj.Initiative,
obj.Attack,
obj.Attack1
};

LINQ - Assign a Value to Anonymous Type's Read Only Property

I would like to create an anonymous type from linq. Then change the value of a single property(status) manually and give the list to a repeater as data source. But doesn't let me do that as theay are read-only. Any suggestion?
var list = from c in db.Mesai
join s in db.MesaiTip on c.mesaiTipID equals s.ID
where c.iseAlimID == iseAlimID
select new
{
tarih = c.mesaiTarih,
mesaiTip = s.ad,
mesaiBaslangic = c.mesaiBaslangic,
mesaiBitis = c.mesaiBitis,
sure = c.sure,
condition = c.onaylandiMi,
status = c.status
};
foreach (var item in list)
{
if (item.condition==null)
{
item.status == "Not Confirmed";
}
}
rpCalisanMesai.DataSource = list.ToList();
rpCalisanMesai.DataBind();
Instead of trying to change the value after creating the list, just set the right value while creating the list.
var list = from c in db.Mesai
join s in db.MesaiTip on c.mesaiTipID equals s.ID
where c.iseAlimID == iseAlimID
select new
{
tarih = c.mesaiTarih,
mesaiTip = s.ad,
mesaiBaslangic = c.mesaiBaslangic,
mesaiBitis = c.mesaiBitis,
sure = c.sure,
condition = c.onaylandiMi,
status = c.onaylandiMi != null ? c.status : "Not Confirmed"
};
Also, if you could change the property, your problem would be executing the query twice: first in the foreach-loop, and then again by calling list.ToList() (which would create new instances of the anonymous type).
You cannot, anonymous type's properties are read-only.
You need to set it during object creation. See #Dominic answer for code sample.
You can. For instance:
var data = (from a in db.Mesai select new { ... status = new List<string>() .. }).ToList();
Next, compute your status:
foreach (var item in data) {
item.status.Add("My computed status");
}
And then on rendering:
foreach (var item data) {
Response.Write(item.status[0]);
}
EDIT: The list can even be intialized as per your requirement:
var data = (from a in db.Mesai select new { ... status = new List<string>(new
string[] { c.status }) .. }).ToList();
foreach (var item in data) {
item.status[0] = "My computed status";
}
EDIT2: Seems like you must initialize the list, preferably with e.g. c.rowid.ToString(), otherwise the optimizer assigns the same new List() to all items, thinking that this might be some game or something.

Linq query change from List<string> to List<T> where clause

I have a linq query that works when it I had a list of a single value now that I change to having a List that has several properties I need to change the where clause
So this works:
List<string> etchList = new List<string>();
etchList.Add("24");
var etchVect = (from vio in AddPlas
where etchList.Any(v => vio.Key.Formatted.Equals(v))
let firstOrDefault = vio.Shapes.FirstOrDefault()
where firstOrDefault != null
select new
{
EtchVectors = firstOrDefault.Formatted
}).ToList();
However I have a new hard coded list (which will represent incoming data:
List<ExcelViolations> excelViolations = new List<ExcelViolations>();
excelViolations.Add(new ExcelViolations
{
VioID = 24,
RuleType = "SPACING",
VioType = "Line-Line",
XCoordinate = 6132,
YCoordinate = 10031.46
});
So the NEW Linq query looks like this, but is obviously will not work as
AddPlas is a List and so using this other list of excelviolations, I wish to have it do where on each one of the properties in the excelviolations list
var etchVect = (from vio in AddPlas
where excelViolations.Any(vioId => vio.Key.Formatted.Equals(vioId))
let firstOrDefault = vio.Shapes.FirstOrDefault()
select new
{
EtchVectors = firstOrDefault.Formatted
}).ToList();
Now, since this is a list within a list, I would like to do something like add in each of the properties
so for example:
where excelViolations.VioID.Any(vioId => vio.Key.Formatted.Equals(vioId))
However that is not possible, but you see that I'm trying to access the property of VioID that is in the excelViolations and match it to the Key which is in vio list
Just change this line
where excelViolations.Any(vioId => vio.Key.Formatted.Equals(vioId))
to
where excelViolations.Any(excelVio => vio.Key.Formatted.Equals(excelVio.VioID))
then i thought it will works

String.Split in a Linq-To-SQL Query?

I have a database table that contains an nvarchar column like this:
1|12.6|18|19
I have a Business Object that has a Decimal[] property.
My LINQ Query looks like this:
var temp = from r in db.SomeTable select new BusinessObject {
// Other BusinessObject Properties snipped as they are straight 1:1
MeterValues = r.MeterValues.Split('|').Select(Decimal.Parse).ToArray()
};
var result = temp.ToArray();
This throws an NotSupportedException: Method 'System.String[] Split(Char[])' has no supported translation to SQL.
That kinda sucks :) Is there any way I can do this without having to add a string property to the business object or selecting an anonymous type and then iterating through it?
My current "solution" is:
var temp = from r in db.SomeTable select new {
mv = r.MeterValues,
bo = new BusinessObject { // all the other fields }
};
var result = new List<BusinessObject>();
foreach(var t in temp) {
var bo = t.bo;
bo.MeterValues = t.mv.Split('|').Select(Decimal.Parse).ToArray();
result.Add(bo);
}
return result.ToArray(); // The Method returns BusinessObject[]
That's kinda ugly though, with that temporary list.
I've tried adding a let mv = r.MeterValues.Split('|').Select(Decimal.Parse).ToArray() but that essentially leads to the same NotSupportedException.
This is .net 3.5SP1 if that matters.
You need to force the select clause to run on the client by calling .AsEnumerable() first:
var result = db.SomeTable.AsEnumerable().Select(r => new BusinessObject {
...
MeterValues = r.MeterValues.Split('|').Select(Decimal.Parse).ToArray()
}).ToList();
You can't use split, but in this scenario you can do the following:
// Database value is 1|12.6|18|19
string valueToFind = "19";
var temp = from r in db.SomeTable.Where(r => ("|" + r.MeterValues + "|").Contains("|" + valueToFind + "|"));
This code adds outer pipes (|) to the database value on the fly inside the query so you can do start, middle, and end value matches on the string.
For example, the above code looks for "|19|" inside "|1|12.6|18|19|", which is found and valid. This will work for any other valueToFind.
You don't need to use a temporary list:
var query = from r in db.SomeTable
select new
{
r.Id,
r.Name,
r.MeterValues,
...
};
var temp = from x in query.AsEnumerable()
select new BusinessObject
{
Id = x.Id,
Name = x.Name,
MeterValues = x.mv.Split('|').Select(Decimal.Parse).ToArray(),
...
};
return temp.ToArray();
Unfortunately its the IQueryable you are using (Linq to SQL) that is not supporting the Split function.
You are really only left with the IEnumerable (Linq to Objects) support for it in this case. You second code snippet is what you need to do, or something like...
var temp = (from r in db.SomeTable select new {
mv = r.MeterValues,
bo = new BusinessObject { // all the other fields }
}).AsEnumerable().Select(blah, blah) ;

Categories