Combine two rows of data using LINQ/SQL - c#

I have a situation where my query returns the following two rows:
UserName ID Designation RoleID
shd.1234 3 1 2
shd.1234 3 1 5
I am able to display these results in a Jqgrid using LINQ.
However I want to display it as under in a single row:(if RoleID is 5, display it in another column in the same row.)
UserName ID Designation RoleID AdditionalRoleID
shd.1234 3 1 2 5
My current query is something like this:
empDetails = (from u in ObjectContext.USERS
join ed in ObjectContext.USERS_EMPLOYEE_DETAILS on u.UserID equals ed.UserID
join r in ObjectContext.ROLES_FOR_USERS on u.UserID equals r.UserID
join ro in ObjectContext.ROLES on r.RoleID equals ro.RoleID
where (r.HospitalID == Context.CurrentUser.HIdentity.HospitalID)
where(r.RoleID!= 4)
select new Models.AdminModelSettings.EmployeeDetailsForGivenHospital
{
UserName = u.UserName,
EmployeeId = ed.ID,
EmployeeDesignation = ed.Designation,
RoleID = r.RoleID,
RoleName = r.RoleID == 1 || r.RoleID == 2 || r.RoleID == 3 ? ro.RoleName : null,
AdditionalRole = r.RoleID == 5 ? ro.RoleName : null
}).ToList();
I would please like to know how this can be done in SQL/LINQ.

UPDATE: I've improved the code so it will do all of the work in SQL instead of returning the results and then performing the grouping.
This should do the trick!
The key part is where we order the rows by RoleID and then group the rows by ID. It assumes that you only have a Role and an Additional Role, i.e. it won't select an AdditionalRole2 or AdditionalRole3, etc...
var empDetails = from u in ObjectContext.USERS
join ed in ObjectContext.USERS_EMPLOYEE_DETAILS on u.UserID equals ed.UserID
join r in ObjectContext.ROLES_FOR_USERS on u.UserID equals r.UserID
join ro in ObjectContext.ROLES on r.RoleID equals ro.RoleID
where (r.HospitalID == Context.CurrentUser.HIdentity.HospitalID)
where(r.RoleID!= 4)
select new Models.AdminModelSettings.EmployeeDetailsForGivenHospital
{
UserName = u.UserName,
EmployeeId = ed.ID,
EmployeeDesignation = ed.Designation,
RoleID = r.RoleID,
RoleName = r.RoleID == 1 || r.RoleID == 2 || r.RoleID == 3 ? ro.RoleName : null
});
var roleIDs = new List<int> { 1, 2, 3 };
//group our results and order the group by the role id
var temp = empDetails.GroupBy(row => row.ID).Select(g => new { First = g.FirstOrDefault(r => roleIDs.Contains(r.RoleID)), Last = g.FirstOrDefault(r => r.RoleID == 5) });
//select the data into the shape that we want
var query = temp.Select(result => new Models.AdminModelSettings.EmployeeDetailsForGivenHospital
{
UserName = (result.First ?? result.Last).UserName,
EmployeeId = (result.First ?? result.Last).ID,
EmployeeDesignation = (result.First ?? result.Last).Designation,
RoleID = (result.First == null) ? (int?)null : result.First.RoleID,
AdditionalRoleID = (result.Last == null) ? (int?)null : result.Last.RoleID
});

Related

how do i ignore tables with no rows and return values from other tables in linq

I'm working on this conference app where I have to return certain values from the different table using join queries using LINQ
from a in db.ApplySchedule
join b in db.userdetails on a.UserID equals b.UserId
join c in db.roomdetails on a.RoomID equals c.RoomId
join d in db.VideoFiles on a.RoomID equals d.RoomId where d.IsActive == true || d.IsActive==false
join e in db.ImageFiles on a.RoomID equals e.RoomId where e.IsActive == true|| e.IsActive==false
where EntityFunctions.TruncateTime(a.MDate) == EntityFunctions.TruncateTime(DateTime.Now) && a.RoomID == id
&& a.Status == true
select new ShedulerViewModel
{
Id = a.BookingID,
UserId = a.UserID,
Uname = b.UserName,
RoomId = a.RoomID,
Rname = c.RoomName.ToUpper(),
Organizer = a.SubjectDetail,
Date = a.MDate,
FromTime = a.start_date,
ToTime = a.end_date,
//Accesseries = a.Accesseries,
attend = a.Attend,
VideoID = d.RoomId,
VideoPath = d.FilePath,
videoIsActive= d.IsActive,
ImageId = e.RoomId,
ImagePath = e.FilePath,
ImageIsActive = e.IsActive
};
Here is the problem, I'm able to get the values if the last two tables db.imagefiles and db.videofiles has matching values but incase it doesn't I'm getting 0 value from all the other tables even though there are rows with matching id, how do I overcome this? I want to pass value even if the video and image tables have no rows.

c# LINQ how to properly pass a method into the select and return the value

I have a LINQ query that I'm trying to pass a method into it and then return the results back to the select statement.
There are no errors being thrown but UpdatedYesterday contains nothing even through GetUpdatedValue(int r) is returning a yes or no. Is a way to get the returned value in the select statement ?
For example
var result = (from r in reportOne
join l in logs on r.id equals l.id into g
select new TestReport
{
UserID = r.UserID,
UpdatedDate = r.UpdatedDate,
UpdatedYesterday = g.Where(x => x.LogDate == r.WorkDate)
.Select(x => GetUpdatedValue(x.updatedYesterday)).FirstOrDefault()
}).ToList();
public string GetUpdatedValue(int r)
{
var value = r > 0 ? "Yes" : "No";
return value;
}
I think that your WorkDate can not be the same as LogDate, it's better to use just date difference, without time.
Try this
var result = (from r in reportOne
join l in logs
on r.Id equals l.Id into lg
from l in lg.DefaultIfEmpty()
where EF.Functions.DateDiffDay(r.WorkDate, r.LogDate )==0
select new TestReport
{
UserID = r.UserID,
UpdatedDate = r.UpdatedDate,
UpdatedYesterday=l.UpdatedYesterday > 0 ? "Yes" : "No"
}).ToList();
but if for some reasons you still want to use your method, the easiest way is to add one extra property to TestReport
public UpdatedYesterdayInt int {get; set;}
code
var query=
.....
select new TestReport
{
UserID = r.UserID,
UpdatedDate = r.UpdatedDate,
UpdatedYesterdayInt=l.UpdatedYesterday
}).ToList();
var result=query.ForEach(i=> i.UpdatedYesterday=GetUpdatedValue(i.UpdatedYesterdayInt));

Linq with conditional joins

I couldn't convert the following left join SQL to linq:
select Students.StudentID, StudentAddresses.state
from Students left join Studentaddresses on (Students.StudentID = Studentaddresses.StudentID and StudentAddresses.Active=1)
where (StudentAddresses.Rank =1 or StudentAddresses.StudentID is null)
and Students.StudentID =3
A student can have zero record or multiple records in the Student Address table, but only one of the records can be active and rank=1.
I was able to do a left join in linq and make it work for normal situation. But if a student has two inactive records in the Student table, I don't know how to make the student record appear only once in the final result. Can anyone please help?
Use Distinct() to collapse duplicates.
var LeftJoin = (from student in Students
join address in (from address1 in StudentAddresses where address.Active select address1)
on student.StudentID equals address.StudentId
into JoinedStudentAddress
from joined in JoinedStudentAddress.DefaultIfEmpty()
select new
{
StudentID = student.StudentID,
State = joined != null ? joined.State : null
}).Distinct();
Alternate syntax
var LeftJoin = Students.GroupJoin( StudentAddress.Where( a => a.Active ),
s => s.StudentID,
a => a.StudentID,
(s,a) => new { Student = s, Addresses = a } )
.SelectMany( j = > j.Addresses.DefaultIfEmpty()
(s,a) => new {
StudentID = s.Student.StudentID,
State = a != null ? a.State : null
})
.Distinct();
This would be the SQL statement converted to linq:
var q = from student in Students
from adress in Studentaddresses.Where(x => student.StudentID == x.StudentID && x.Active).DefaultIfEmpty()
where (adress.Rank == 1 || adress.StudentID == null) && student.StudentID == 3
select new
{
StudentID = student.StudentID,
State = adress.state
};

Grouping troubles

Hi i am having difficulties to group these data as it has no aggregate function. I have the following data in 2 tables and i would like to Join both by PaymentId and display only 1 row of record.
Question:
How do i display the final result in only 1 ROW groupby CoursePaidForMonthYear.
I would like to get all data from Payment.*, TutorCourseCommissions.* and CoursePaidForMonthYear column in same row displaying (September, October, November)
Example:
referenceId| TutorId| CoursePaidForMonthYear |
1 | 1019 | September, October, November OR 9,10,11|
My work:
var result = from u in db.Users
join p in db.Payments on u.Id equals p.UserId
join tt in db.TutorCourseCommissions on p.Id equals tt.PaymentId into gtt
from tt in gtt.DefaultIfEmpty()
where u.Id == user.Id
GroupBy tt.CoursePaidForMonthYear ??
select new { u, p, tt };
foreach (var r in result)
{
Payment payment = new Payment();
payment.MonthToPay = (r.tt == null) ? null : common.GetMonthName(r.tt.CoursePaidForMonthYear.Month, true);
payment.Amount = r.p.Amount;
output.Add(payment);
}
return output;
What you need to do is group the months by the user and payment, and then perform an aggregation on the grouped months. In this case I used String.Join() to combine the distinct months coming from the commission.
This will give you results along the lines of { User = "John Doe", Payment = ..., Months = "January, February" }
var result = from u in db.Users
where u.UserID == user.Id
join p in db.Payments on u.Id equals p.UserId
join comm in db.TutorCourseCommissions
on p.Id equals comm.PaymentId
group common.GetMonthName(comm.CoursePaidForMonthYear,true)
by new { User = u, Payment = p } into g
select new
{
User = g.Key.User,
Payment = g.Key.Payment,
//...select out other properties here...
Months = String.Join(", ", g.Distinct())
};
Made a class with properties regarding all columns you required and then do the selection using its instance ...
Like
public TutorPayments
{
public int UserID{
get;
set;
}
public int PayType{
get;
set;
}
public int TutorID{
get;
set;
}
//and so on all columns property that you required
}
now you can get all these in your query by creating its instance in this way
var result = from u in db.Users
join p in db.Payments on u.Id equals p.UserId
join tt in db.TutorCourseCommissions on p.Id equals tt.PaymentId into gtt
from tt in gtt.DefaultIfEmpty()
where u.Id == user.Id
GroupBy tt.CoursePaidForMonthYear ??
select new TutorPayments {UserID = u.id,PayType = p.id,TutorID = tt.TutorId, ............ };

Linq to Sql Localisation query

Given the following tables I'd like to return the localised text for given culture or the text for the default culture where no row exist for the given culture.
diagram http://lh4.ggpht.com/_gjsCWAV_CZc/ShW6hC-eozI/AAAAAAAACbY/mXaBfiZtBY8/s400/diagram.png
So with the folowing data
Resources
ID Name
1 Donkey
2 Elephant
LocaleStrings
ID CultureID ResID LocaleText
1 1 1 Donkey
2 1 2 Elephant
3 2 1 baudet
I'd like to be able to return the following for the French culture
baudet
elephant
I've tried various queries based around LEFT JOINS samples I've seen but I'm stuck.
var ct = from r in db.Resources
join lt in db.LocaleStrings
on r.ID equals lt.ResID into res
from x in res.DefaultIfEmpty()
select new
{
CultureID = x.CultureID,
LocaleText = x.LocaleText,
ResID = x.ResID
};
var text =
from c in db.Cultures
join t in ct
on c.ID equals t.CultureID into cults
from x in cults.DefaultIfEmpty()
select x;
I'm sure there's a better way, but this seems to work:
var ct =
from c in db.Cultures
from l in db.LocaleStrings
from r in db.Resources
where r.ID == l.ResID
select new
{
CultureID = c.ID,
LocaleText = l.CultureID == c.ID ? l.LocaleText : r.Name,
ResID = r.ID,
LSID = l.CultureID == c.ID ? l.ID : 0
};
var text =
from t in ct
where t.LSID != 0 || (t.LSID == 0 && !((from ac2 in ct
where ac2.LSID > 0 && ac2.CultureID == t.CultureID
select ac2.ResID).Contains(t.ResID)))
select new
{
CultureID = t.CultureID,
LocaleText = t.LocaleText,
ResID = t.ResID
};

Categories