LINQ grouping/subquery to fill a hierarchy data strcuture - linq

I have a DataTable that queries out something like below
usergroupid...userid......username
1.............1...........John
1.............2...........Lisa
2.............3...........Nathan
3.............4...........Tim
What I'm trying to do is write a LINQ statement that will return an array of UserGroup instances. The UserGroup class has properties of UserGroupId and Users. Users is an array of User instances. The User class then has properties of UserId and UserName.
Can filling such a hierarchy be done with a single LINQ statement and what would it look like?
Thanks a million

Check this out, hope this helps
var users = new[]
{
new {UserGroupId = 1, UserId = 1, UserName = "John"},
new {UserGroupId = 1, UserId = 2, UserName = "Lisa"},
new {UserGroupId = 2, UserId = 3, UserName = "Nathan"},
new {UserGroupId = 3, UserId = 4, UserName = "Tim"}
};
var userGroups = from user in users
group user by user.UserGroupId into userGroup
select new {
UserGroupId = userGroup.Key,
Users = userGroup.ToList()
};
foreach (var group in userGroups)
{
Console.WriteLine("{0} - {1}",group.UserGroupId, group.Users.Count);
}

There is - look at GroupBy and Select methods.

Related

LINQ perform select and insert in single query

I am working on Entity Framework 6 in C# .NET CORE 2.0 application. I have requirement to get role id from database where roleName = x and add role reference to user as in one: many table
I want to avoid 2 trip to database, I want to do in one go or in single Linq query
UserDataModel userObj = new UserDataModel()
{
Id = fakeUserID,
Name = "k1",
Surname = "z",
Email = "k.z#yahoo.co.uk",
Roles = new List<UserRoleDataModel>
{
new UserRoleDataModel {
UserId = fakeUserID,
RoleId = Context.Roles.Where(roleName => roleName.Name == RoleName).Select(x=>x.Id)
}
}
};
Context.Add<UserModel>(userObj);
Context.SaveChanges();
above code gives me error at RoleId
refer in screen shot;
Error because you are assigning IQueryable to a Property of type Int (I Assumed its Int). You should do this:
RoleId = Context.Roles.Where(roleName => roleName.Name == RoleName && roleName.Id==Id).Select(x=>x.Id).First();

How to Execute a method inside LINQ to Entities'

var users = from u in db.UserProfiles select new UsersViewModel{
UserName = u.UserName,
UserId = u.UserId,
IsDisabled = u.IsDisabled,
Role = Roles.GetRolesForUser(u.UserName).FirstOrDefault()
};
I would like to select the roles from the database and create a list of UsersViewModel. However Entity Framework is trying to execute the projection on the SQL side, where there is no equivalent to Roles.GetRolesForUser.
What would be an alternative to this or how am I suppose to execute any method inside the query?
The easiest is to get the data you want from SQL, then after the query executes, iterate through the results and populate the additional details from the function in your code.
Example:
var users = (from u in db.UserProfiles select new UsersViewModel{
UserName = u.UserName,
UserId = u.UserId,
IsDisabled = u.IsDisabled
}).ToList();
foreach(var user in users){
user.Role = Roles.GetRolesForUser(u.UserName).FirstOrDefault();
}
The key to remember here is to separate out what you're doing (understanding the separation of concerns in your architecture). Take care of the SQL first, then augment the data from other sources, in your case the Role Provider.
You can force the query to execute before creating the ViewModels by adding ToList():
var users = from u in db.UserProfiles.ToList()
select new UsersViewModel{
UserName = u.UserName,
UserId = u.UserId,
IsDisabled = u.IsDisabled,
Role = Roles.GetRolesForUser(u.UserName).FirstOrDefault()
};
As CodeMonkey1313 noted, I strongly suggest you apply some sort of filter in your query:
var users = from u in db.UserProfiles
.Where( x => /* apply filter here */ )
.ToList() //Force query to execute
select new UsersViewModel {
UserName = u.UserName,
UserId = u.UserId,
IsDisabled = u.IsDisabled,
Role = Roles.GetRolesForUser(u.UserName).FirstOrDefault()
};
You can convert your Queryable to an Enumerable that executes locally:
var users = (from u in db.UserProfiles select new UsersViewModel{
UserName = u.UserName,
UserId = u.UserId,
IsDisabled = u.IsDisabled)}
).AsEnumerable()
.Select(u => new {
UserName = u.UserName,
UserId = u.UserId,
IsDisabled = u.IsDisabled,
Role = Roles.GetRolesForUser(u.UserName) })
.FirstOrDefault()

How do you filter a list based on matching items in another list?

I have an Organisation object
public class Organisation
{
OrgId {get....}
OrgName {get...}
AccountTypes { get....} //this is of type List<AccountType>
}
and an AccountType object
public class AccountType
{
AccountTypeId {get....}
AccountTypeName {get...}
}
I'm looking for a way to look through the existing Organisations List and remove AccountTypes from each organisation where the account types are not found in another list of AccountTypes (which would be a post back from a browser).
Would I do something like?
var foundOrgs = from org in orgs
where org.OrganisationId == Convert.ToInt32(hash["orgId"])
select org;
Organisation organisation = foundOrgs.ElementAt(0);
organisation.AccountTypes.Clear();
organisation.AccountTypes = // What goes here?
I'm looking to do a Linq query that will compare one list with another and return only those items where the AccountTypeIDs match, or are present.
You can use List<T>.RemoveAll:
// where accounts is IEnumerable<int>
organisation.AccountTypes.RemoveAll(at => !accounts.Contains(at.AccountTypeId));
EDITED CODE
//created account id list over here
var AccountTypeID = accountType.Select(x=>x. AccountTypeId);
//you code
var foundOrgs = from org in orgs
where org.OrganisationId == Convert.ToInt32(hash["orgId"])
select org;
Organisation organisation = foundOrgs.ElementAt(0);
organisation.AccountTypes.Clear();
//changes in code where you want to change -// What goes here?
List<AccountTypes> templist = organisation.AccountTypes;
organisation.AccountTypes =
from acc in templist
where !AccountTypeID.Conains(acc.AccountTypeId)
select acc).ToList();
EDIT
No sure but you can try out
var orgdata= from org in foundOrgs
select { OrgId =org.OrgId ,OrgName = org.OrgName ,
AccountTypes = ( from acc in org.AccountTypes
where !AccountTypeID.Conains(acc.AccountTypeId)
select acc) };
Try something like this
var ids = {1, 2, 3};
var query = from item in context.items
where !ids.Contains( item.id )
select item;
this will give you list of element which are not part of 1,2,3 i.e ids list , same you can apply in you code first find out which are not there and than remove it from the list
Image

Issue To Select/Show DropDown Selected Value At Edit() In Asp.net MVC 3

I Using Two Table User And Location In User Table I having LocationId And When I'm going to edit The User Form Then I need User With There Exact Location In Drop Down.but i didn't get that this is my code Of Controller:-
LogisticsEntities db = new LogisticsEntities();
RegisterModel Reg = new RegisterModel();
var tempUser = (from c in db.Users select new RegisterModel { _UserId = c.UserID, UserName = c.Name, Code = c.Code, Email = c.Email, Phone = c.Phone, JobRole = c.JobRole, StartDate = c.StartDate, EndDate = c.EndDate, LocationId = c.Location }).SingleOrDefault(x => x._UserId == id);
var varLocation = from Ls in db.Locations select Ls;
ViewData["LocationId"] = new SelectList(varLocation.ToList(), "LocationID", "Location1", "2");
if (tempUser != null)
return View(tempUser);
else
return View();
And In My View I Have code: -
#Html.DropDownList("LocationID", (SelectList)ViewData["LocationId"])
Thanx In Advance..
You are using LocationID as both first parameter of the dropdown and inside ViewData. In order to generate a dropdown you need 2 things: the first argument will be used to generate the name attribute of the dropdown and used to bind the value back and the second argument must represent a collection of SelectListItem that will be used to create the options of the dropdown. So try using a different key for the collection:
ViewData["locations"] = new SelectList(varLocation.ToList(), "LocationID", "Location1", "2");
and then:
#Html.DropDownList("LocationID", (SelectList)ViewData["locations"])

Linq To Entities - how to filter on child entities

I have entities Group and User.
the Group entity has Users property which is a list of Users.
User has a property named IsEnabled.
I want to write a linq query that returns a list of Groups, which only consists of Users whose IsEnabled is true.
so for example, for data like below
AllGroups
Group A
User 1 (IsEnabled = true)
User 2 (IsEnabled = true)
User 3 (IsEnabled = false)
Group B
User 4 (IsEnabled = true)
User 5 (IsEnabled = false)
User 6 (IsEnabled = false)
I want to get
FilteredGroups
Group A
User 1 (IsEnabled = true)
User 2 (IsEnabled = true)
Group B
User 4 (IsEnabled = true)
I tried the following query, but Visual Studio tells me that
[Property or indexer 'Users' cannot be assigned to -- it is read only]
FilteredGroups = AllGroups.Select(g => new Group()
{
ID = g.ID,
Name = g.Name,
...
Users = g.Users.Where(u => u.IsInactive == false)
});
thank you for your help!
There is no "nice" way of doing this, but you could try this - project both, Group and filtered Users onto an anonymous object, and then Select just the Groups:
var resultObjectList = AllGroups.
Select(g => new
{
GroupItem = g,
UserItems = g.Users.Where(u => !u.IsInactive)
}).ToList();
FilteredGroups = resultObjectList.Select(i => i.GroupItem).ToList();
This isn't a documented feature and has to do with the way EF constructs SQL queries - in this case it should filter out the child collection, so your FilteredGroups list will only contain active users.
If this works, you can try merging the code:
FilteredGroups = AllGroups.
Select(g => new
{
GroupItem = g,
UserItems = g.Users.Where(u => !u.IsInactive)
}).
Select(r => r.GroupItem).
ToList();
(This is untested and the outcome depends on how EF will process the second Select, so it would be nice if you let us know which method works after you've tried it).
I managed to do this by turning the query upside down:
var users = (from user in Users.Include("Group")
where user.IsEnabled
select user).ToList().AsQueryable()
from (user in users
select user.Group).Distinct()
By using the ToList() you force a roundtrip to the database which is required because otherwise the deferred execution comes in the way. The second query only re-orders the retrieved data.
Note: You might not be able to udpate your entities afterwards!
try something like this and you'll still have your entities:
FilteredGroups = AllGroups.Select(g => new
{
Group = g,
Users = g.Users.Where(u => u.IsInactive == false)
}).AsEnumerable().Select(i => i.Group);
That way you should still be able to use Group.Users
If you want to retain your entity structure, try this:
var userGroups = context.Users.Where(u => !u.IsInactive).GroupBy(u => u.Group);
foreach (var userGroup in userGroups)
{
// Do group stuff, e.g.:
foreach (var user in userGroup)
{
}
}
And you certainly can modify your entities!
Use inner linq query
var FilteredGroups = (from g in AllGroups
select new Group()
{
ID = g.ID,
Name = g.Name,
...
Users = (from user in g.Users
where user.IsInactive == false
select user).ToList()
});

Resources