LINQ : The query results cannot be enumerated more than once [duplicate] - c#

This question already has answers here:
The result of a query cannot be enumerated more than once
(4 answers)
Closed 9 years ago.
This is my code
searchDataContext db = new searchDataContext();
var query = (from p in db.SearchFirst(city, area)
select new
{
ID = p.Id,
Address = p.address,
Level = p.agahilevel
});
int count =query.Count();
// records
var q = query.Skip(Convert.ToInt32(start)).Take(Convert.ToInt32(width));
if (q.Count() > 0)
{
int index = 0;
str += "[";
foreach (var row in q)
{
if (index == 0)
I have an error in this code
The query results cannot be enumerated more than once.
please check that and answer me.

You cannot use cached queries and iterate over them more than once...
Make a List<T> of it and try it again
var q = query.ToList(); // work on this

Materialize your query:
var addresses = (from p in db.SearchFirst(city, area)
select new
{
ID = p.Id,
Address = p.address,
Level = p.agahilevel
})
.Skip(Convert.ToInt32(start))
.Take(Convert.ToInt32(width))
.ToList();
Then use Enumerable.Any to check if it contains elements:
if(addresses.Any())
{
int index = 0; // ...
}

If you add .ToList() to your query your problem will be solved

Related

Call Function In LinQ Query

I want to sum price for all products that is in list.
I called a funtion in linQ query.
Total = t0.TbOfferProducts.Sum(x => Customs.CalculateCurrency(x.TbOffer.Price))
But it didnt recognize my function
I wrote another function for linQ, then I called it. But linQ dont recognize my function.
Error:
LINQ to Entities does not recognize the method 'Double Cal_Price(Int32)' method, and this method cannot be translated into a store expression.
I try other versions but none of them didnt work.Help me please.
myList =
(from t0 in DB.TbProducts
where t0.BoActive == true && t0.BoSoftDeleted == false
let price = Cal_Price(t0.InProductId)
select new ProductActivityInfo
{
ID = t0.InProductId,
Name = t0.StProductName,
Code = t0.StProductCode,
Total = price
})
public double Cal_Price(int productId)
{
double total = 0;
using (MyEntityContext DB = new MyEntityContext())
{
var list = DB.TbOfferProducts.Where(x => x.InProductId == productId);
foreach (var item in list)
{
total += Customs.CalculateCurrency(item.TbOffer.Price);
}
}
return total;
}
EF Core is tryng to build SQL but fails when found custom compiled method in query. Correct Total on the client side:
// calculate sum by grouping
var offerPrices =
from op in DB.TbOfferProducts
group op.TbOffer.Price by x.InProductId
select new
{
ProductId = g.Key,
RawPrice = g.Sum()
};
var result =
(from t0 in DB.TbProducts
join op in offerPrices on t0.InProductId equals op.ProductId
where t0.BoActive == true && t0.BoSoftDeleted == false
select new ProductActivityInfo
{
ID = t0.InProductId,
Name = t0.StProductName,
Code = t0.StProductCode,
Total = op.RawPrice
})
.ToList();
// correct Total on the client side
result.ForEach(x => x.Total = Customs.CalculateCurrency(x.Total));

Random selection of query result Linq

i have a query which will result 10 or 20 or any number number of rows. Below is the query.
var q = (from c in session.DB.Question where c.Level='1' && c.Group='1' select c);
This query can give me any number of rows.
But i have to show just 1 row from the result. I can select top 1/first but i would like select randomly.
i saw a topic about this: How to request a random row in SQL?
but i want it in LinQ
Please help me how to get random row from the result.
Sort items by random value and select first:
var q = (from c in session.DB.Question
where c.Level =='1' && c.Group =='1'
select c)
.OrderBy(o => SqlFunctions.Rand())
.First();
Thanks all. i found it and working:
var q = (from c in Session.DB.WinQuestionSet
where c.Level == "easy" && c.Grade == "1"
select c).OrderBy(x => Guid.NewGuid()).Take(1).Single();
label1.Text = q.Text;
I assume that your questions has an Id. Please see example below. I used Random class to generate random number.
List<Question> questions = new List<Question>
{
new Question { Id = 10, Name = "What?" },
new Question { Id = 12, Name = "How?" },
new Question { Id = 32, Name = "When?" },
new Question { Id = 41, Name = "Where?" },
};
var q = (from c in questions select c);
int i = 1;
Dictionary<int, int> questionKeys = new Dictionary<int, int>();
foreach (var item in questions)
{
questionKeys.Add(i, item.Id);
i++;
}
Random rdm = new Random();
int randomRow = rdm.Next(1, q.Count());
var questionId = questionKeys.Where(x => x.Key == randomRow).Select(x => x.Value).Single();
var result = q.Where(x => x.Id == questionId).Single();
Console.WriteLine(result.Name);
Assuming data is your data rows:
Random rand = new Random();
var row = data.ElementAt(rand.Next(data.Count));
Note that this does not work for Linq to SQL, and thus should be used after you query your db.

How to add an order(autoIncrement) property to collection using Linq?

Having:
Initialize an anonymouse collection (I would send it as json)
var myCollection = new[]
{
new
{
Code = 0,
Name = "",
OtherAttribute = ""
}
}.ToList();
myCollection.Clear();
And get the data.
myCollection = (from iPeople in ctx.Person
join iAnotherTable in ctx.OtherTable
on iPeople.Fk equals iAnotherTable.FK
...
order by iPeople.Name ascending
select new
{
Code = iPeople.Code,
Name = iPeople.Name,
OtherAttribute = iAnotherTable.OtherAtribute
}).ToList();
I want to add an Identity column, I need the collection ordered and a counted from 1 to collection.count. Is for binding this counter to a Column in a table (jtable).
var myCollection = new[]
{
new
{
Identity = 0,
Code = 0,
Name = "",
OtherAttribute = ""
}
}.ToList();
myCollection = (from iPeople in ctx.Person
join iAnotherTable in ctx.OtherTable
on iPeople.Fk equals iAnotherTable.FK
...
order by iPeople.Name ascending
select new
{
Identity = Enum.Range(1 to n)//Here I donĀ“t know how to do; in pl/sql would be rownum, but in Linq to SQL how?
Code = iPeople.Code,
Name = iPeople.Name,
OtherAttribute = iAnotherTable.OtherAtribute
}).ToList();
If you are using linq to entities or linq to sql, get your data from the server and ToList() it.
Most likely this answer will not translate to sql but I have not tried it.
List<string> myCollection = new List<string>();
myCollection.Add("hello");
myCollection.Add("world");
var result = myCollection.Select((s, i) => new { Identity = i, Value = s }).ToList();
As Simon suggest in comment, that could would look like below:
int counter = 0; //or 1.
myCollection = (from iPeople in ctx.Person
join iAnotherTable in ctx.OtherTable
on iPeople.Fk equals iAnotherTable.FK
...
order by iPeople.Name ascending
select new
{
Identity = counter++,
Code = iPeople.Code,
Name = iPeople.Name,
OtherAttribute = iAnotherTable.OtherAtribute
}).ToList();
Is there any problem in executing this kind of code?
As Simon stated in his comments, consider the following, albeit contrived, example:
int i = 0;
var collection = Enumerable.Range(0, 10).Select(x => new { Id = ++i });
One solution that helped me to achieve the same goal:
Create a separate Function like this:
private int getMaterialOrder(ref int order)
{
return order++;
}
Then call it in your linq query like:
...
select new MaterialItem() { Order=getMaterialOrder(ref order),
...

Save list to to database

I have created a function on my restaurant review site that finds the cuisine of the last review and then finds other reviews of the same cuisines with a greater average score and then saves the restaurant id of those reviews into a table on the database. However I keep on getting the error:
Cannot assign method group to an implicitly-typed local variable.
on the line restaurantid = choices.Any help would be grateful.
var averagescore = db.Reviews
.Where(r => r.Cuisine == review.Cuisine)
.Average(r => r.score);
var choices = (from r in db.Reviews
where r.score <= averagescore
select r.RestaurantId).ToList;
foreach (var item in choices)
{
var suggestion = new Suggestion()
{
id = review.id,
Userid = review.UserId,
restaurantid = choices
};
db.Suggestions.Add(suggestion);
db.SaveChanges();
}
Following line:
var choices = (from ...).ToList;
Should be:
var choices = (from ...).ToList();
Secondly, it looks to me that restaurantid is of type int. With your code you're assigning a List<int> to the int. This should be item, from the loop.
You need to make the following change:
var averagescore = db.Reviews
.Where(r => r.Cuisine == review.Cuisine)
.Average(r => r.score);
var choices = (from r in db.Reviews
where r.score <= averagescore
select r.RestaurantId).ToList;
foreach (var item in choices)
{
var suggestion = new Suggestion()
{
id = review.id,
Userid = review.UserId,
restaurantid = item //here was your problem, you need to assign an id not a list of ids
};
db.Suggestions.Add(suggestion);
db.SaveChanges();
}
Have you tried like this:
var choices = (from r in db.Reviews
where r.score <= averagescore
select r).ToList;
foreach (var item in choices)
{
var suggestion = new Suggestion()
{
id = item.id,
Userid = item.UserId,
restaurantid = item.Restaurantid
};
db.Suggestions.Add(suggestion);
db.SaveChanges();
}

Find the most frequent numbers in an array using LINQ [duplicate]

This question already has answers here:
Find the most occurring number in a List<int>
(6 answers)
Closed 9 years ago.
List<int> a = new List<int>{ 1,1,2,2,3,4,5 };
What's the quickest way to do this with LINQ?
I'm new to LINQ
The key here is using Enumerable.GroupBy and the aggregation method Enumerable.Count:
List<int> list = new List<int>() { 1,1,2,2,3,4,5 };
// group by value and count frequency
var query = from i in list
group i by i into g
select new {g.Key, Count = g.Count()};
// compute the maximum frequency
int whatsTheFrequencyKenneth = query.Max(g => g.Count);
// find the values with that frequency
IEnumerable<int> modes = query
.Where(g => g.Count == whatsTheFrequencyKenneth)
.Select(g => g.Key);
// dump to console
foreach(var mode in modes) {
Console.WriteLine(mode);
}
Jason's answer is correct, but you can perform this operation in one LINQ operation.
List<int> list = new List<int>() { 1, 1, 2, 2, 3, 4, 5 };
// return most frequently occurring items
var query = from i in list
group i by i into g
let maxFreq = (from i2 in list
group i2 by i2 into g2
orderby g2.Count() descending
select g2.Count()).First()
let gCount = g.Count()
where gCount == maxFreq
select g.Key;
// dump to console
foreach (var mode in query)
{
Console.WriteLine(mode);
}
public static Tres MostCommon<Tsrc, Tres>(this IEnumerable<Tsrc> source, Func<Tsrc, Tres> transform)
{
return source.GroupBy(s => transform(s)).OrderByDescending(g => g.Count()).First().Key;
}
And in your example with integral types you can call it as:
List<int> a = new List<int>{ 1,1,2,2,3,4,5 };
int mostCommon = a.MostCommon(x => x);
from num in a
group num by num into numg
let c = numg.Count()
order by c descending
select new { Number = numg.Key, Count = c }
I think the most frequent number can also be achieved in a single query like this-
var query = (from i in list
group i by i into g
orderby g.Count() descending
select new { Key = g.Key, Count = g.Count() }).FirstOrDefault();
if (query == null) Console.WriteLine("query = NULL");
else Console.WriteLine("The number '{0}' occurs {1} times.", query.Key, query.Count);
Null check is not really required but it may be useful when null is actually expected (like Empty list?)

Categories