I am trying to build a query where there is one student name then a nested collection of clubs he belongs to. I want to organize this collection with OrderByDescending. I am stuck with what to provide to the parenthesis.
public void GetStudentsClubNameRev()
{
try
{
using (SchoolContainer = new SchoolContainer())
{
var query = from student in SchoolContainer.Students
select new
{
StudentName = student.Name,
ClubName = student.StudentClubMatches
.Where(s =>s.StudentId == student.Id)
.Select(c => c.Club.Name)
.OrderByDescending(o => "Name")
};
}
}
catch (Exception ex)
{
}
}
In .OrderByDescending(o => "Name") I don't know what my predicate is. I want to say orderbydescending on the Name which is club name. But I get errors because I don't think I understand what it wants.
After you've selected "Club.Name", the current enumerable is just a string. You just want a pass-through selector:
.Select(c => c.Club.Name)
.OrderByDescending(name => name)
If you OrderByDescending before Select you could also do this:
var query = from student in SchoolContainer.Students
select new
{
StudentName = student.Name,
ClubName = student.StudentClubMatches
.Where(s =>s.StudentId == student.Id)
.OrderByDescending(c => c.Club.Name)
.Select(c => c.Club.Name)
};
Cheers
To sort by a property you should use the following:
Code:
.OrderByDescending(o => o.Name)
Related
I have the following simple statement in my Entity Framework code:
query = query
.Where(c => c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault());
It simply finds the latest Notification based on a group by with conversationId and select latest. Easy.
However, this is ONLY what I want if c.NotificationType == NotificationType.AppMessage. If the column is different than AppMessage (c.NotificationType <> NotificationType.AppMessage), I just want the column. What I truly Want to write is a magical statement such as:
query = query
.Where(c => (c.NotificationType <> NotificationType.AppMessage)
|| ((c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault()));
But this doesn't make sense because the GroupBy/Select is based on the first where statement.
How do I solve this?
The simplest way is to compose UNION ALL query using Concat at the end of your original query:
query = query
.Where(c => c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault())
.Concat(query.Where(c => c.NotificationType != NotificationType.AppMessage));
public class EntityClass
{
public int NotificationType { get; set; }
public int ConversationId { get; set; }
public DateTime Created { get; set; }
public static EntityClass GetLastNotification(int convId)
{
var list = new List<EntityClass>(); // Fill the values
list = list
.GroupBy(i => i.ConversationId) // Group by ConversationId.
.ToDictionary(i => i.Key, n => n.ToList()) // Create dictionary.
.Where(i => i.Key == convId) // Filter by ConversationId.
.SelectMany(i => i.Value) // Project multiple lists to ONLY one list.
.ToList(); // Create list.
// Now, you can filter it:
// 0 - NotificationType.AppMessage
// I didn't get what exactly you want to filter there, but this should give you an idea.
var lastNotification = list.OrderByDescending(i => i.Created).FirstOrDefault(i => i.NotificationType == 0);
return lastNotification;
}
}
you filter your list with "GroupBy" based on ConversationId. Next, create a dictionary from the result and make only one list (SelectMany). Then, you already have one list where should be only records with ConversationId you want.
Last part is for filtering this list - you wanted to last notification with certain NotificationType. Should be working :)
I'm trying to select multiple columns not in a group by using linq - c#.
Using linq, I'm trying to group by ISNULL(fieldOne,''),ISNULL(fieldTo,'') and then select field_One, field_Two, field_Three for each group. So for each row that the group by would return, I want to see numerous rows.
So far I have the following, but can't seem to select all the needed columns.
var xy = tableQueryable.Where(
!string.IsNullOrEmpty(cust.field_One)
|| ! string.IsNullOrEmpty(ust.field_Two)
).GroupBy(cust=> new { field_One= cust.field_One ?? string.Empty, field_Tow = cust.field_Two ?? string.Empty}).Where(g=>g.Count()>1).AsQueryable();
Can somebody help pls?
You are pretty much there - all you are missing is a Select from the group:
var xy = tableQueryable
.Where(!string.IsNullOrEmpty(cust.first_name) || ! string.IsNullOrEmpty(ust.lastName))
.GroupBy(cust=> new { first_name = cust.first_name ?? string.Empty, last_name = cust.last_name ?? string.Empty})
.Where(g=>g.Count()>1)
.ToList() // Try to work around the cross-apply issue
.SelectMany(g => g.Select(cust => new {
Id = cust.Id
, cust.FirstName
, cust.LastName
, cust.RepId
}));
Select from each group does the projection of the fields that you want, while SelectMany dumps all the results into a flat list.
Would this work for you?
var groupsWithDuplicates = tableQueryable
.Where(c => !string.IsNullOrWhiteSpace(c.first_name) || !string.IsNullOrWhiteSpace(c.last_name))
.GroupBy(c => new { FirstName = c.first_name ?? "", LastName = c.last_name ?? "" })
.Where(group => group.Count() > 1) // Only keep groups with more than one item
.ToList();
var duplicates = groupsWithDuplicates
.SelectMany(g => g) // Flatten out groups into a single collection
.Select(c => new { c.first_name, c.last_name, c.customer_rep_id });
For me I have used following query to do the filter Customer and get the customer records group by the JobFunction. In my case the issue get resolved after adding the .AsEnumerable() after the where solve the problem.
var query = _context.Customer
.Where(x => x.JobTitle.ToUpper().Contains(searchText.ToUpper())).AsEnumerable()
.GroupBy(item => item.JobFunction,
(key, group) => new {
JobFunction = key,
CustomerRecords = group.ToList().Select(c => c).ToList()
})
.ToList();
I have a Dictionary:
var dict = new Dictionary<int, string>();
With this values:
[0]: {[1, "Person1"]}
[1]: {[2, "Person2, Person3"]}
[2]: {[3, "Person4"]}
[3]: {[4, "Person5"]}
And when i use a "foreach" to get the values with "id" 2 i get as result "Person2, Person3".
foreach (var test in dict)
{
if (test.Key == 2)
System.Diagnostics.Debug.WriteLine(test.Value);
}
But when i use this LINQ line:
Person = dict.FirstOrDefault(q => q.Key == s.Person.ID).Value.ToString(),
I get this error:
Local sequence cannot be used in LINQ to SQL implementations of query
operators except the Contains operator.
I tried several things but nothing seems to work, so any ideas?
EDIT
I use this to show output on my page:
DataSelectionQuery = p => new
{
p.ID,
p.FirstName,
p.LastName,
TEST = dict.FirstOrDefault(q => q.Key == p.ID).Value.ToString(),
};
public Expression<Func<LinqClass, object>> DataSelectionQuery { get; set; }
And here is where it trows the error:
var results = query.Select(DataSelectionQuery).ToList();
You cannot use this kind of expressions inside Linq to SQL as they cannot be translated to SQL query
Use .ToList() at the end of your query, then use Linq to objects to complete your entity with values from Dictionary
For example when you have code like:
var result = from x in table
select new Entity
{
Id = x.Id,
Sth = x.Sth,
Person = dict.FirstOrDefault(q => q.Key == s.Person.ID).Value.ToString()
};
You need to change it to something like this:
var result = (from x in table
select new { x.Id, x.Sth, x.PersonId }) // LINQ To SQL part
.ToList() // get query results
.Select(x => new Entity
{
Id = x.Id,
Sth = x.Sth,
Person = dict.FirstOrDefault(q => q.Key == x.PersonId).Value.ToString()
}; // this part will be executed with Linq to objects
Please provide the full source code if you need more detailed help
Ok, so your "SelectionQuery" needs to be simple enough to translate into SQL query and should look like this:
DataSelectionQuery = p => new
{
p.ID,
p.FirstName,
p.LastName
};
And the other part should look like this:
var results = query.Select(DataSelectionQuery).ToList()
.Select(p => new
{
p.ID,
p.FirstName,
p.LastName,
TEST = dict.FirstOrDefault(q => q.Key == p.ID).Value.ToString()
});
Alernatively you can create your own class which will contain the Dictionary and will translate the ID into TEST on the getter action
This is how I solved the problem:
Person = string.Join(", ", PersonsQuery.Where(q => q.ID == s.ID).Select(q => q.PersonInformation))
Below are the linq query. Here I want to add one condition .
Condition : If : Firstname is not empty then select list
where (d=>d.firstname=="Firstname")
else: select all list without condition
function Ponits(string Firstname)
{
pointsCore.Categories.SelectMany(c => c.Events).Select(e => new
{
e.Firstname,
e.Surname,
e.EntityNumber,
e.Eventdate
}).ToList()
}
Two options:
First, optionally use Where:
var events = pointsCore.Categories.SelectMany(c => c.Events);
if (!string.IsNullOrEmpty(firstName))
{
events = events.Where(e => e.Firstname == firstName);
}
var result = events.Select(e => new { ... });
Second: make your Where clause check firstName:
var events = pointsCore.Categories.SelectMany(c => c.Events);
.Where(e => string.IsNullOrEmpty(firstName) ||
e.Firstname == firstName)
.Select(e => new { ... });
Note that due to the lazy evaluation in LINQ, the first option won't involve fetching all the values and then querying; you're still just building up a query.
.Where(d => string.IsNullOrEmpty(Firstname) || d.firstname==Firstname)
I have a bunch of data in a database that i want to write a search function for. The problem is that i'm getting many duplicates.
The data is structured in Names and Surnames and i want to only send one unique of both so if i have two people with the first name Foo, and surname Bar only one will show.
No matter how I think of it I always come back to that I need to compare them.
var names = db.People
.Where(r => r.Name.Contains(q))
.OrderBy(r=> r.Name)
*Psuedo-Code*
if((this.Name==next.Name)&&(this.surSame==next.Surname)
toss next data and loop to next
*Psuedo-Code*
.Take(5);
Maybe a bit messy, but you get the idea what I want to achieve. Can I do this in some way or is there any better way to go about it?
You could do this:
var names = db.People
.Where(r => r.Name.Contains(q))
.Select(r => new { Name = r.Name, Surname = r.Surname })
.Distinct()
.Take(5);
But if that won't work because you need the whole People record, you just want the first, I've done something like this with success:
var names = db.People
.Where(r => r.Name.Contains(q))
.GroupBy(r => new { Name = r.Name, Surname = r.Surname })
.Select(g => g.First())
.Take(5);
Distinct utilizing Equals on People class would be the correct way, but here's an alternative that is more "inline":
var names = db.People
.Where(r => r.Name.Contains(q))
.GroupBy(r => new { r.Name, r.Surname })
.Select(g => g.First())
.OrderBy(r => r.Name)
.Take(5);
Use Distinct() and implement the method Equals in People class, or use an auxiliary class to compare them:
public class PeopleComparer : IEqualityComparer<People>
{
public bool Equals(People x, People y)
{
return x.Name == y.Name && x.Surname == y.Surname;
}
public int GetHashCode(People obj)
{
unchecked
{
return (obj.Name.GetHashCode() * 31) + obj.Surname.GetHashCode();
}
}
}