Entity Framework: String concat in database query - entity-framework

I need to create a string concatenation with an linq statement. I have the following data:
Section
Id: 1, Title: Test1
Id: 2, Title: Test2
Section_User
SectionId: 1, UserId: 1
SectionId: 1, UserId: 2
Users
Id: 1, Name: User1
Id: 2, Name: User2
I need the following result:
SectionId: 1, Users: User1, User2
I create the following Linq statement:
var query2 = from section in this.context.Sections
from users in section.Users
group section by section2.Id into groupedSection
select new {
SectionId = groupedSection.Key,
Users = string.Join(",", users.Select (x => x.Name)) // compile error, but I don't know how I write the statement correctly
};
Could someone tell me, how I can create a string concatenation on database side (not in-memory) with an linq statement.
Thanks!!

Based on #Alexei 's link in the comments, your line should look like
var query2 = from section in this.context.Sections
from users in section.Users
group section by section2.Id into groupedSection
select new {
SectionId = groupedSection.Key,
Users = string.Join(",", (from u in users select s.Name).ToArray())
};
However, if that doesn't work due to LINQ to Entities error, and you're willing to simply leave Users as an IEnumerable<string>, you can simply use:
var query2 = from section in this.context.Sections
from users in section.Users
group section by section2.Id into groupedSection
select new {
SectionId = groupedSection.Key,
Users = (from u in users select s.Name)
};
And later whenever needed, you can join the strings, or display the names using a loop.

Related

LINQ query for joining multiple tables and get comma separated values in single row

I have below tables with the values.
Account:
Id
Name
Email
101
Nasir Uddin
nasir#email.com
Role:
Id
Title
101
Admin
102
Operator
AccountRole:
AccountId
RoleId
101
101
101
102
Now I want to write a linq to have the result like below:
UserAccount
AccountId
Name
Email
Roles
101
Nasir Uddin
nasir#email.com
Admin, Operator
To get the above result I have written the below query in LINQ. But it does not get the expected result.
var userAccount1 = (from account in _db.Accounts
join accountRole in _db.AccountRoles on account.Id equals accountRole.AccountId
join role in _db.Roles on accountRole.RoleId equals role.Id
select new UserAccountInfo
{
AccountId = account.Id,
Name = account.UserFullName,
Email = account.Email,
Roles = string.Join(",", role.Title)
});
At last I found my answer. The results can be achieved in different ways. Examples are given below:
var answer1 = (from account in userAccounts
join accountRole in accountRoles on account.Id equals accountRole.AccountId
join role in roles on accountRole.RoleId equals role.Id
select new UserAccount
{
AccountId = account.Id,
Name = account.Name,
Email = account.Email,
Roles = role.Title
}).ToList().GroupBy(x => new { x.AccountId, x.Name, x.Email }).Select(y => new UserAccount
{
AccountId = y.Key.AccountId,
Name = y.Key.Name,
Email = y.Key.Email,
Roles = string.Join(", ", y.Select(a => a.Roles))
}).ToList();
----------------------------------------------------------------------------
var answer2 = (from account in userAccounts
join accountRole in accountRoles on account.Id equals accountRole.AccountId
join role in roles on accountRole.RoleId equals role.Id
group new { account, role } by new { account.Id, account.Name, account.Email } into ag
select new UserAccount
{
AccountId = ag.Key.Id,
Name = ag.Key.Name,
Email = ag.Key.Email,
Roles = string.Join(", ", ag.Select(x=> x.role.Title))
}).ToList();
----------------------------------------------------------------------------
var answer3 = (from account in userAccounts
let roles1 = from accountRole in accountRoles
join role in roles on accountRole.RoleId equals role.Id
where accountRole.AccountId == account.Id
select role
select new UserAccount
{
AccountId = account.Id,
Name = account.Name,
Email = account.Email,
Roles = string.Join(", ", roles1.Select(x => x.Title))
}).ToList();
The below gives you the expected result using Lambda Expression (not Query Expression) based on the information provided in your post (and some assumptions since I could not find e.g. UserFullName in any of your tables)
Note: I'm also convinced there is a more efficient way to do this, but it is a starting point if nothing else.
(Here is working .NET Fiddle of the below: https://dotnetfiddle.net/aGra15):
// Join the AccountRoles and Roles together and group all Titles for
// a given AccountId together
var groupedAccountRoles = AccountRoles.GroupJoin(Roles, i => i.RoleId, o => o.Id, (o, i) => new {o, i})
.Select(x => new {AccountId = x.o.AccountId, Titles = string.Join(",", x.i.Select(y => y.Title))});
// Perform another GroupJoin to group by AccountId and Join to groupedAccountRoles table. Then `string.Join()`
var userAccount1 = Accounts.GroupJoin(AccountRoles, acc => acc.Id, accrol => accrol.AccountId,
(o, i) => new {o, UserAccountRoles = i})
.GroupJoin(groupedAccountRoles, ii => ii.o.Id, oo => oo.AccountId,
(ii, oo) => new UserAccountInfo
{
AccountId = ii.o.Id,
Email = ii.o.Email,
Name = ii.o.Name,
Roles = string.Join(",", oo.Select(x => x.Titles))
});
This will give the following output:

how to write distinct count query in Linq

suppose i have a following query in Sql
select UserID,count(distinct ip) as NumberOfIPUsed from UserLogs
group by UserID
i want this to write with Linq
Well, first you're going to want to group by UserID:
UserLogs.GroupBy(ul => ul.UserID)
Then you want to get the UserID and the count of distinct ip from that:
UserLogs.GroupBy(ul => ul.UserID).Select(g => new {UserID = g.Key, Count = g.Select(ul => ul.ip).Distinct().Count()})
You need to use the Distinct function which isn't available directly in comprehension expressions, so some functional style is required:
var res = await (from ul in context.UserLogs
group ul by ul.UserId into grouped
select new {
UserId = grouped.Key,
Count = group.Select(x => x.ip).Distinct().Count()
}).ToListAsync();

How to save Father and Child document with MongooseJS

I'm quite new in MongoDB & MongooseJS. Actually learning the MEAN stack, I already love it.
I'm not sure to exactly understand noSQL principles, sorry If I duplicate.
I want to join 2 documents, type father and child, with 1 to N relationship.
Here's two solutions:
• Sub documents: http://mongoosejs.com/docs/subdocs.html
• References: http://mongoosejs.com/docs/populate.html
I've chosen the first one, simpler and IHMO closer to my problem.
Here's the code:
var personSchema = new Schema({
name : String
});
var groupSchema = new Schema({
name : String,
persons : [ personSchema ]
});
var Group = module.exports = mongoose.model('Group', groupSchema);
var Person = module.exports = mongoose.model('Person', personSchema);
Group.findById(groupId, function(err, group) {
var person = new Person();
person.name = "john";
group.persons.push(person);
group.save();
});
When I check for all groups, it work perfectly. The groups are returned, with the people saved.
Group.find(function(err, group) {
// group is full of groups & people
}
But when I check for person, nothing is returned.
Person.find(function(err, person) {
// person is empty
}
It seems that only the Group table document was filled. Is the solution implies to save 1/ the person and 2/ the group, and if so, will Person be saved in two different places (in Group document and in Person document)?
Group.findById(groupId, function(err, group) {
var person = new Person();
person.name = "john";
group.persons.push(person);
person.save(function(...) {
group.save();
});
});
Thanks

.Include in following query does not include really

var diaryEntries = (from entry in repository.GetQuery<OnlineDiary.Internal.Model.DiaryEntry>()
.Include("DiaryEntryGradeChangeLog")
.Include("DiaryEntryAction")
join diary in repository.GetQuery<OnlineDiary.Internal.Model.OnlineDiary>()
on entry.DiaryId equals diary.Id
group entry
by diary
into diaryEntriesGroup
select new { Diary = diaryEntriesGroup.Key,
DiaryEntry = diaryEntriesGroup.OrderByDescending(diaryEntry => diaryEntry.DateModified).FirstOrDefault(),
});
This query does not include "DiaryEntryGradeChangeLog" and "DiaryEntryAction" navigation properties, what is wrong in this query?
I have removed join from the query and corrected as per below, and still it populates nothing
var diaryEntries = from entry in repository.GetQuery<OnlineDiary.Internal.Model.DiaryEntry>()
.Include("DiaryEntryGradeChangeLog").Include("DiaryEntryAction")
.Where(e => 1 == 1)
group entry
by entry.OnlineDiary
into diaryEntryGroups
select
new { DiaryEntry = diaryEntryGroups.OrderByDescending(diaryEntry => diaryEntry.DateModified).FirstOrDefault() };
It will not. Include works only if the shape of the query does not change (by design). If you use this query it will work because the shape of the query is still same (OnlineDiary.Internal.Model.DiaryEntry):
var diaryEntries = (from entry in repository.GetQuery<OnlineDiary.Internal.Model.DiaryEntry>()
.Include("DiaryEntryGradeChangeLog")
.Include("DiaryEntryAction");
But once you use manual join, grouping or projection (select new { }) you have changed the shape of the query and all Include calls are skipped.
Edit:
You must use something like this (untested) to get related data:
var diaryEntries = from entry in repository.GetQuery<OnlineDiary.Internal.Model.DiaryEntry>()
group entry by entry.OnlineDiary into diaryEntryGroups
let data = diaryEntryGroups.OrderByDescending(diaryEntry => diaryEntry.DateModified).FirstOrDefault()
select new {
DiaryEntry = data,
GradeChangeLog = data.DiaryEntryGradeChangeLog,
Action = data.DiaryEntryAction
};
or any similar query where you manually populate property for relation in projection to anonymous or unmapped type.

EF - how to add Relationship between 2 tables and insert refrenceId in the masterTable?

For example I have 3 tables:
Users -- the master table
{ Id, Name }
Permissions -- details
{ Id, PermissionTitle }
UserPermissions -- is a relation table between User and its Permissions
{ UserId , PermissionId}
I have 2 users in the tbUsers ( {1,"user1"} , {2,"user2"} )
and I have 3 permissions in the tbPermissions ( {1,"perm1"} , {2,"perm2"} , {3,"perm3"} )
now I want to add perm1 and perm2 to user1. What should I do in EF?
(I don't want to create/insert any Users or Permissions, I just want to add a relationship between them in the relation table)
because of EF, I don't have UserPermissions table in my dataModel.
If you want to load entities first you can do:
using (var context = new YourContext())
{
var user1 = context.Users.Single(u => u.Id == 1);
var perm1 = context.Permissions.Single(p => p.Id == 1);
var perm1 = context.Permissions.Single(p => p.Id == 2);
user1.Permissions.Add(perm1);
user1.Permissions.Add(perm2);
context.SaveChanges();
}
If you know Ids and you don't want to load entities first you can do:
using (var context = new YourContext())
{
var user1 = new User {Id = 1};
var perm1 = new Permission {Id = 1};
var perm1 = new Permission {Id = 2};
context.Users.Attach(user1);
context.Permissions.Attach(perm1);
context.Permissions.Attach(perm2);
user1.Permissions.Add(perm1);
user1.Permissions.Add(perm2);
context.SaveChanges();
}
These two approaches can be combined - for example you can load user from DB and create dummy objects only for permissions.
Users should have a navigation property Permissions so you need to add the permission to that collection. Should look similar to this:
user.Permissions.Add(permission1);
user.Permissions.Add(permission2);
context.SaveChanges();