I'm newbie to LINQ.
I will like to get know what's the highest value for 'Question Position' and i want increase it by 1 for new Question and save it into database from MVC 4 view.
My db data : (highest position value is 2)
====================
Question | Position
====================
Q1 | 1
Q2 | 2
After added new Question : ( increment the highest position (2) + 1 )
====================
Question | Position
====================
Q1 | 1
Q2 | 2
Q3 | 3
My Code :
var query =
db.SURV_Question_Model
.Where(r => r.Question_Survey_ID == viewModel.Survey_ID)
.GroupBy(r => new { r.Question_Position })
.Select(grp => grp.OrderByDescending(i => i.Question_Position).FirstOrDefault());
After i get the highest value from query, can i do something like below?
* int i = query.Question_Position + 1 ???
Appreciate your guidance.
You can use Max:
var maxId = db.SURV_Question_Model
.Where(r => r.Question_Survey_ID == viewModel.Survey_ID)
.Max(x => x.Position);
But, if there is not any record it will throw an exception. So, it will be better to change your code as:
var maxId = ...Max(x => (int?)x.Position) ?? 0;
You don't need the GorupBy method, this should be enough:
var maxId =
db.SURV_Question_Model
.Where(r => r.Question_Survey_ID == viewModel.Survey_ID)
.OrderByDescending(x => x.Position)
.FirstOrDefault());
I actually don't know the usage of the where condition, I left there anyway.
Related
I have a dataset that i want to groupby to determine duplicate data.
Example i have a dataset that looks like this.
|id | Number | ContactID
1 1234 5
2 9873 6
3 1234 7
4 9873 6
Now i want to select data that has more than one occurrence of Number but only if the ContactID is not the same.
So basically return
| Number | Count |
1234 2
Any help would be appreciated using LINQ to EF, thanks.
Update:
All thanks to #DrCopyPaste, as he told me that I misunderstood your problem. Here is the correct solution:-
var result = from c in db.list
group c by c.Number into g
let count = g.GroupBy(x => x.ContactID).Where(x => x.Count() == 1).Count()
where count != 0
select new
{
Number = g.Key,
Count = count
};
Sample Fiddle.
This query avoids making a custom IEqualityComparer as if I remember correctly don't think they play well with EF.
var results = data.GroupBy(number => number.Number)
.Where(number => number.Count() > 1)
.Select(number => new
{
Number = number.Key,
Count = number.GroupBy(contactId => contactId.ContactId).Count(x => x.Count() == 1)
})
.Where(x => x.Count > 0).ToList();
Fiddle
It does an initial GroupBy to get all Numbers that are duplicated. It then selects a new type that contains the number and a second GroupBy that groups by ContactId then counts all groups with exactly one entry. Then it takes all results whose count is greater than zero.
Have not testing it against EF, but the query uses only standard Linq operators so EF shouldn't have any issues translating it.
Another way of doing this(using 1 level of grouping):
var results = data
.Where(x => data.Any(y => y.Id != x.Id && y.Number == x.Number && y.ContactId != x.ContactId))
.GroupBy(x => x.Number)
.Select(grp => new { Number = grp.Key, Count = grp.Count() })
.ToList();
Fiddle
i am very new with C# and MVC.
My Problem:
I have a list OF IDs
int[] mylist = {10, 23}
I try to query some data from DB
var result = db.tableName.Where(o => mylist.Any(y => y == o.item_ID && o.readed)).ToList();
This is what I get with the query:
item_ID Product_ID readed
277 1232 1
277 1233 1
277 1235 1
280 1235 1
What I need is:
item_ID Product_ID readed
277 1235 1
280 1235 1
If I change "any" to "all" i don't get any results, but I have definitely one item where the condition fits.
I think its more like make a query with id 277, then a query with 280 and then merge the list and return only where where "Product_ID" match.
Any ideas?
I assume that what you need is this:
var temp = db.tableName.Where(o => mylist.Any(y => y == o.item_ID && o.readed))
.ToList();
// Find the Product_id which appeared more than one time
// By the way, this assumes that there is at least one product_Id whihc has appeared more than one time
var neededProductID = temp.GroupBy(x => x.Product_ID)
.Where(x => x.Count() > 1)
.First()
.Key;
// Filter the result by neededProductID
var result = temp.Where(x => x.Product_ID == neededProductID).ToList();
Also, if there could be more tha one Product_ID which has apperaed more than one time, then you can consider this:
var neededProductID = temp.GroupBy(x => x.Product_ID)
.Where(x => x.Count() > 1)
.Select(x => x.Key)
.ToList();
var result = temp.Where(x => neededProductID.Any(y => y == x.Product_ID)).ToList();
By the way, you don't need All(). It tells you if all the elements in a collection match a certain condition.
You can use the following
var result = db.tableName.Where(o => mylist.conains(o.item_ID)
&& o.readed).ToList();
Let's say I have a table with the following data:
Id | title | image | page
-------------------------
1 test a.jpg 1
2 test b.jpg 2
3 test 1 c.jpg 1
4 test 1 d.jpg 2
How would I go about grouping the data by title and retrieving the first results. Like so:
Id | title | image | page
-------------------------
1 test a.jpg 1
3 test 1 c.jpg 1
What I have tried so far but without luck is:
var result = _db.Records.Select(r => new Records
{
Id = r.Id,
title = r.title,
image = r.image,
page = r.page
}).OrderByDescending(x => x.Id)
.GroupBy(x => x.title)
.Select(x => x.First()).AsQueryable();
Am I going about this the right way? Any help appreciated.
Why order by and why return AsQueryable? This is what I have done. If you must return a queryable, appending AsQueryable() will still work.
Records.GroupBy (r => r.Title)
.Select (r =>r.First ())
The first Select doesn't seem to do anything. You already have Records and you're selecting Records.
The second Select is also not needed. Instead of calling x => x.First() why not call First() ? Or am I missing something?
var result = _db.Records
//.OrderByDescending(x => x.Id)
.GroupBy(x => x.title)
.First();
Edit: the OrderBy is doing work that is negated (somewhat) by the GroupBy
Edit 2: The above will only get the first group. So the x => x.First() was correct:
var result = _db.Records
.GroupBy(x => x.title)
.Select(group => group.First());
var results
= _db.Records.GroupBy(
i => i.title,
(key, group) => group.First()
)
Hope this helps
I currently have this code:
foreach (var newsToPolitician in news.NewsToPoliticians)
{
var politician = newsToPolitician.Politician;
var votes = (from s in db.Scores
where o.IDPolitician == politician.IDPolitician
&& o.IDNews == IDNews
group o by o.IDAtribute
into g
select new{
Atribute= g.Key,
TotalScore= g.Sum(x => x.Score)
}).ToList();
}
It works alright, but I want to avoid making multiple queries to my database in foreach loop.
My table Scores looks like this:
IDScore | IDNews | IDUser | IDPolitician | IDAtribute | Score
1 40 1010 35 1 1
2 40 1010 35 2 -1
3 40 1002 35 1 1
4 40 1002 35 2 1
5 40 1002 40 1 -1
...
My goal is to aggregate all the scores for all politicians in a news. A news can have up to 7 politicians.
Is it expensive to call my database up to seven times in a foreach loop. I know that isn't best practice so I'm interested is there any way to avoid it in this particular case and make one call to database and then process it on the server side?
Update - Due to user comments have re-jigged to try and ensure aggregation on the server.
In this case we can group on the server by both IDPolitician and IDAttribute and then pull the groups in with ToLookup locally as so:
var result = db.Scores.Where(s => s.IDNews == IDNews)
.Where(s => news.NewsToPoliticians
.Select(n => n.Politician.IDPolitician)
.Contains(s.IDPolitician))
.GroupBy(s => new
{
s.IDPolitician,
s.IDAttribute
},
(k,g ) => new
{
k.IDPolitician,
k.IDAttribute,
Sum = g.Sum(x => x.Score)
})
.ToLookup(anon => anon.IDPolitician,
anon => new { anon.IDAttribute, anon.Sum })
Legacy -
You want to use GroupJoin here, it would be something along the lines of:
var result = news.NewsToPoliticians
.GroupJoin( db.Scores.Where(s= > s.IDNews == IDNews),
p => p.IDPolitician,
s => s.IDPolitician,
(k,g) => new
{
PoliticianId = k,
GroupedVotes = g.GroupBy(s => s.IDAtribute,
(id, group) => new
{
Atribute = id,
TotalScore = group.Sum(x => x.Score)
})
})
.ToList();
However you are at the mercy of your provider as to how it translates this so it might still be multiple queries to get round this you could use something like:
var politicianIds = news.NewsToPoliticians.Select(p => p.IDPolitician).ToList()
var result = db.Scores.Where(s= > s.IDNews == IDNews)
.Where(s => politicianIds.Contains(s.IDPolitician))
.GroupBy(p => p.IDPolitician,
(k,g) => new
{
PoliticianId = k,
GroupedVotes = g.GroupBy(s => s.IDAtribute,
(id, group) => new
{
Atribute = id,
TotalScore = group.Sum(x => x.Score)
})
})
.ToList();
Which hopefully should be at most 2 query (depending on whether NewsToPoliticians is db dependent). You'll just have to try it out and see.
Use a stored procedure and get the SQL server engine to do all the work. You can still use Linq to call the stored procedure and this will minimize all the calls to the database
Say I've got 2 lists that look something like
ID | IsChipCollected | IsShirtCollected | IsPackCollected
A 0 1 0 1
1 0 1 0
2 0 0 1
B 0 0 1 0
1 0 0 1
2 1 1 1
Basically I need to compare and merge the 2 lists and if a certain flag has been set to say true in B, i should select it instead of A
I know how to achieve this with a single column, but I'm struggling wrapping my head around doing it in a scenario with 2+ columns
var result = A.Concat(B)
.GroupBy(x => x.Id)
.Select(g => g.OrderByDescending(x => x.IsShirtCollected).First())
I'll update my code sample if i make any progress on this, (as I'm currently still hacking away :P)
Expected Result
ID | IsChipCollected | IsShirtCollected | IsPackCollected
0 1 1 1
1 0 1 1
2 1 1 1
var result = A.Concat(B)
.GroupBy(x => x.Id)
.Select(g => new {//or new <A and B's generic type>, then change the underCode with proper case
id = g.Key,
isShipCollected = g.Max(m => m.IsChipCollected),
isShirtCollected = g.Max(m => m.IsShirtCollected),
isPackCollected = g.Max(m => m.IsPackCollected)
});
Edit
Following Servy's (good) idea (changing 1 / 0 to boolean values)
var result = A.Concat(B)
.GroupBy(x => x.Id)
.Select(g => new {
id = g.Key,
isShipCollected = g.Any(m => m.IsChipCollected == 1),
isShirtCollected = g.Any(m => m.IsShirtCollected == 1),
isPackCollected = g.Any(m => m.IsPackCollected == 1)
});
Not sure if it would be faster/slower than a concat/groupby, but technically the operation that you're performing is a Join, so it makes more sense in terms of readability to actually perform that join.
var query = listA.Join(listB, item => item.ID, item => item.ID,
(a, b) => new
{
ID = a.ID,
IsChipCollected = a.IsChipCollected | b.IsChipCollected,
IsShirtCollected = a.IsShirtCollected | b.IsShirtCollected,
IsPackCollected = a.IsPackCollected | b.IsPackCollected,
});