I want to get rows with the count column and sum column like in the SQL command ... count(column1.table1) as countname, sum(column2.table1) as sumname ..., but I don't know the right way to write it in Linq, for the example:
var get = (from dbrg in db.data_barangs
join pbrg in db.pengiriman_barangs
on dbrg.kode_barang equals pbrg.kode_barang
join jdkp in db.jadwal_kapals
on pbrg.id_jadwal equals jdkp.id_jadwal
join dplb in db.data_pelabuhans
on jdkp.kode_pelabuhan equals dplb.kode_pelabuhan
join drdp in db.data_redpacks
on dbrg.kode_barang equals drdp.kode_barang
select new
{
KodeBarang = dbrg.kode_barang,
TanggalKedatangan = jdkp.tgl_kedatangan,
WaktuKedatangan = jdkp.waktu_kedatangan,
NamaPelabuhan = dplb.nama_pelabuhan,
Kota = dplb.kota,
Provinsi = dplb.provinsi,
NamaKapal = jdkp.kapal,
JumlahPacking = drdp.id_jadwal.Count(),
TotalBerat = drdp.total_berat_packing.Sum()
}).ToList();
Do you guys know the correct way?
The comments above correctly saying that group by should be used.
It is also good to know what keys should be used in the group by. In the select above you are listing a lot of properties and two of them should be grouped. Please take consider adding and removing some columns.
Why remove columns? Because of performance. If more columns used to group id_jadwal and total_berat_packing that has a cost at database level.
You may ask why add more columns? This can be because of correct functionality. Right now you have seven classic property, these are enough for correct summation? If not add more columns and create index for those
I did modify the query to fulfil grouping if you have question please let me know in the comment section.
var result = (from dbrg in db.data_barangs
join pbrg in db.pengiriman_barangs
on dbrg.kode_barang equals pbrg.kode_barang
join jdkp in db.jadwal_kapals
on pbrg.id_jadwal equals jdkp.id_jadwal
join dplb in db.data_pelabuhans
on jdkp.kode_pelabuhan equals dplb.kode_pelabuhan
join drdp in db.data_redpacks
on dbrg.kode_barang equals drdp.kode_barang
group new { JumlahPacking = drdp.id_jadwal, TotalBerat = drdp.total_berat_packing }
by new {
KodeBarang = dbrg.kode_barang,
TanggalKedatangan = jdkp.tgl_kedatangan,
WaktuKedatangan = jdkp.waktu_kedatangan,
NamaPelabuhan = dplb.nama_pelabuhan,
Kota = dplb.kota,
Provinsi = dplb.provinsi,
NamaKapal = jdkp.kapal,
}
into beratAndPackingSumGroup
select new
{
KodeBarang = beratAndPackingSumGroup.Key.KodeBarang,
TanggalKedatangan = beratAndPackingSumGroup.Key.TanggalKedatangan,
WaktuKedatangan = beratAndPackingSumGroup.Key.WaktuKedatangan,
NamaPelabuhan = beratAndPackingSumGroup.Key.NamaPelabuhan,
Kota = beratAndPackingSumGroup.Key.Kota,
Provinsi = beratAndPackingSumGroup.Key.Provinsi,
NamaKapal = beratAndPackingSumGroup.Key.NamaKapal,
JumlahPacking = beratAndPackingSumGroup.Select(x => x.JumlahPacking).Count(),
TotalBerat = beratAndPackingSumGroup.Sum(x => x.TotalBerat)
});
If JumlahPacking property is not correct you can call a distinction on it: beratAndPackingSumGroup.Select(x => x.JumlahPacking).Distinct().Count() this is require more performance.
Related
how can i convert rows to column in entity framework!?
i have a result like this:
and i want this result:
my entity code i this :
(from loanPerson in context.LoanPersons.AsParallel()
join warranter in context.Warranters.AsParallel() on loanPerson.Id equals warranter.LoanPersonId
where loanPerson.Id == 84829
select new
{
loanPersonId = loanPerson.Id,
waranterId = warranter.WarranterPersonID,
}).ToList();
and number of the row always less than 3 and i want to have 3 column.
please let me know your answer.
tanks.
This query will return the only one row, where waranterIds will contain, at this particular case, three WarranterPersonID values, also this field is of List<int> type, because it's quantity not known at compile time:
var answer = (from loanPerson in context.LoanPersons.Where(x => x.Id == 84829)
join warranter in context.Warranters
on loanPerson.Id equals warranter.LoanPersonId
group warranter by loanPerson.Id into sub
select new
{
loanPersonId = sub.Key,
waranterIds = sub.Select(x => x.LoanPersonId).ToList()
//if you sure, that quantity equals 3,
//you can write this code instead of waranterIds:
//zamen1 = sub.Select(x => x.LoanPersonId).First(),
//zamen2 = sub.Select(x => x.LoanPersonId).Skip(1).First(),
//zamen3 = sub.Select(x => x.LoanPersonId).Skip(2).First()
}).ToList();
I am implementing a controller and I need to get all staff members which have a certain RiskTypeID, which will be selected by the user when they click on Navigation Item.
Here is how I would create the joins in SQL
SQL
Select
RTHG.RiskTypeID,
SM.FullName
From RiskTypeHasGroup RTHG
Inner join RiskGroup RG On RTHG.RiskGroupID = RG.ID
Inner join RiskGroupHasGroupMembers RGHGM ON RG.ID = RGHGM.RiskGroupID
Inner Join GroupMember GM ON RGHGM.GroupMemberID = GM.ID
Inner Join GroupMemberHasStaffMember GMHSM ON GM.ID = GMHSM.GroupMemberID
Inner Join StaffMember SM ON GMHSM.StaffMemberID = SM.ID
Where RTHG.RiskTypeID = 1
I’ve pulled back data before using Linq and lambda but only using simple expressions, I now need to be able to make a call which will bring back the same data as the sql outlined above, I’ve searched online but can’t find anything similar to my requirement.
Here is my Controller, I placed comments inside as guidance
Controller
public ActionResult ViewRiskTypes(int SelectedRiskTypeID)
{
var RiskTypes = _DBContext.RiskTypes.ToList(); // Get all of the current items held in RiskTypes tables, store them as a List in Var RiskTypes
var ViewModel = new List<RiskTypeWithDetails>(); // Create colletion which holds instances of RiskTypeWithDetails and pass them to the ViewModel
var Details = new RiskTypeWithDetails(); // Create a new instance of RiskType with details and store the instance in var Details
foreach (var RiskType in RiskTypes) // Loop through each Item held in var RiskTypes
{
Details.RiskTypes.Add(new RiskTypesItem { ID = RiskType.ID, Description = RiskType.Description }); // assign each items ID & Description to the same feilds in a new
// instance of RiskTypeItems (which is a property of RiskTypeWithDetails)
}
foreach (var RiskType in RiskTypes) // Loop through each item in RiskTypes
{
if (RiskType.ID == SelectedRiskTypeID) // Check Item ID matches SelectedRiskTypeID value
{
//var Details = new RiskTypeWithDetails();
Details.RiskTypeDescription = RiskType.Description; //assign the Risk type Descripton to RiskTypeWithDetails RiskTypeDescription Property
Details.RiskDetails = _DBContext
.RiskTypeHasGroups
//.GroupMemberTypeHasGroupMembers
.Where(r => r.RiskTypeID == SelectedRiskTypeID) // Where RiskTypeId matches Selected ID bring back following data from Db
.Select(r => new RiskDetails
{
RiskGroupDescription = r.RiskGroup.Description,
GroupMembers = r.RiskGroup.RiskGroupHasGroupMembers
.Select(v => v.GroupMember).ToList(),
//StaffMembers = r.RiskGroup.RiskTypeHasGroups
// .Join(r.RiskGroup.RiskTypeHasGroups,
// a => a.RiskGroupID , b => b.RiskGroup.ID,
// (a, b) => new {a, b})
// .Join(r.RiskGroup.RiskGroupHasGroupMembers,
// c => c.) // Dosent join as I would expect... no idea what to do here
}).ToList();
ViewModel.Add(Details); //Add all data retrieved to the ViewModel (This creates one item in the collection)
}
}
return View(ViewModel);
}
As you will see I want to get all Staff Members with a match for the selected RiskTypeID. I need some assistance in converting the above SQL to work within my controller as a lambda expression
Thanks in advance
You were on the right track with your commented out code! For starters, LINQ has two different sytaxes: query and method chain. You were using the method chain syntax and it can get really unmaintainable really quickly.
For an instance like this, query syntax is where it's at.
Here's the result:
from rhtg in _dbContext.RiskTypeHasGroup
where rhtg.RiskTypeID == 1
join rg in _dbContext.RiskGroup
on rhtg.RiskGroupID equals rg.ID
join rghgm in _dbContext.RiskGroupHasGroupMembers
on rg.ID equals rhtg.ID
join gm in _dbContext.GroupMember
on rg.ID equals gm.ID
join gmhsm in _dbContext.GroupMemberHasStaffMember
on gm.ID equals gmhsm.GroupMemberID
join sm in _dbContext.StaffMember
on gmhsm.StaffMemberID equals sm.ID
select new
{
rhtg.RiskTypeId,
sm.FullName
};
Do note, that I used .Net conventions for the different variables.
Here's some documentation on the query syntax:
https://msdn.microsoft.com/en-us/library/gg509017.aspx
You can write the exact same query in linq as follows:
var query = (from RTHG in _DBContext.RiskTypeHasGroup RTHG
join RG in _DBContext.RiskGroup on RTHG.RiskGroupID equals RG.ID
join RGHGM in _DBContext.RiskGroupHasGroupMembers on RG.ID equals RGHGM.RiskGroupID
join GM in _DBContext.GroupMember on RGHGM.GroupMemberID = GM.ID
join GMHSM in _DBContext.GroupMemberHasStaffMember on GM.ID equals GMHSM.GroupMemberID
join SM in _DBContext.StaffMember on GMHSM.StaffMemberID equals SM.ID
where RTHG.RiskTypeID == 1
select new {RTHG.RiskTypeID,SM.FullName});
Kindly convert my SQL to LINQ. I'm really desperate. It includes multiple filtering (2).
SELECT dbo.EmployeeAccess.EmpNo,
dbo.View_SystemAdminMembers.LNameByFName,
dbo.View_SystemAdminMembers.GroupName,
dbo.View_SystemAdminMembers.Role,
dbo.View_SystemAdminMembers.Active,
dbo.View_SystemAdminMembers.EmpNo AS Expr4,
dbo.View_SystemAdminMembers.RoleID
FROM dbo.EmployeeAccess
INNER JOIN dbo.View_SystemAdminMembers
ON dbo.EmployeeAccess.GroupID = dbo.View_SystemAdminMembers.GroupID
WHERE (dbo.EmployeeAccess.EmpNo = '50')
Thank you so much in advance.
Please try with the below code snippet.
var result =from e in context.EmployeeAccess
join v in context.View_SystemAdminMembers on e.GroupID equals v.GroupID
Where e.EmpNo == 50
select new { e.EmpNo,v.LNameByFName,v.GroupName,v.Role,v.Active,a.RoleID,v.EmpNo as VEmpNo };
Note : context is your DB Context object.
Let me know if any concern.
var results = (from ea in DbContext.EmployeeAccess
join sam in DbContext.View_SystemAdminMembers on ea.GroupId equals sam.GroupId
where ea.EmpNo = '50'
select new {
ea.EmpNo,
sam.LNameByFName,
sam.GroupName,
sam.Role,
sam.Active,
Expr4 = sam.EmpNo,
sam.RoleID
};
You didnt mention what your database context was, you'll have to fill that in yourself.
var res = (from x in ctx.EmployeeAccess
join y in ctx.View_SystemAdminMembers on x.GroupId equals y.groupId
where x.EmpNo = '50'
select new
{
x.EmpNo,
y.LNameByFName,
y.GroupName,
y.Role,
y.Active,
Expr4 = y.EmpNo,
y.RoleID
});
Note: do NOT use = when joining, but equals.
er have the following query in linq...
Whenever I try to run it I get a No comparison operator for type System.Int[] exception.
It's got something to do with the dictionary I am sure, but I don't understand why this isn't valid and was wondering if someone could explain?
// As requested... not sure it will help though.
var per = (
from p in OtherContext.tblPeriod
where activeContractList.Select(c => c.DomainSetExtensionCode).Contains(p.DomainSetExtensionCode)
select p).ToArray();
var com = (
from c in MyContext.tblService
join sce in MyContext.tblServiceExtension
on c.ServiceExtensionCode equals sce.ServiceExtensionCode
join sc in MyContext.tblServiceContract
on sce.ServiceContractCode equals sc.ContractCode
group sc by c.Period into comG
select new
{
PeriodNumber = comG.Key,
Group = comG,
}).ToArray();
var code =
(from c in com
join p in per on c.PeriodNumber equals p.PeriodNumber
select new
{
p.Code,
c.Group
}).ToArray();
var payDictionary = new Dictionary<int, int[]>();
// This is another linq query that returns an anonymous type with
// two properties, and int and an array.
code.ForEach(c => payDictionary.Add(c.Code, c.Group.Select(g => g.Code).ToArray()));
// MyContext is a LINQ to SQL DataContext
var stuff = (
from
p in MyContext.tblPaySomething
join cae in MyContext.tblSomethingElse
on p.PaymentCode equals cae.PaymentCode
join ca in MyContext.tblAnotherThing
on cae.SomeCode equals ca.SomeCode
where
// ca.ContractCode.Value in an int?, that should always have a value.
payDictionary[p.Code].Contains(ca.ContractCode.Value)
select new
{
p.Code,
p.ExtensionCode,
p.IsFlagged,
p.Narrative,
p.PayCode,
ca.BookCode,
cae.Status
}).ToList();
You won't be able to do this with a dictionary. The alternative is to join the three linq queries into one. You can do this with minimal impact to your code by not materializing the queries with ToArray. This will leave com and code as IQueryable<T> and allow for you compose other queries with them.
You will also need to use a group rather than constructing a dictionary. Something like this should work:
var per = (
from p in OtherContext.tblPeriod
where activeContractList.Select(c => c.DomainSetExtensionCode).Contains(p.DomainSetExtensionCode)
select p.PeriodNumber).ToArray(); // Leave this ToArray because it's materialized from OtherContext
var com =
from c in MyContext.tblService
join sce in MyContext.tblServiceExtension on c.ServiceExtensionCode equals sce.ServiceExtensionCode
join sc in MyContext.tblServiceContract on sce.ServiceContractCode equals sc.ContractCode
group sc by c.Period into comG
select new
{
PeriodNumber = comG.Key,
Group = comG,
}; // no ToArray
var code =
from c in com
where per.Contains(c.PeriodNumber) // have to change this line because per comes from OtherContext
select new
{
Code = c.PeriodNumber,
c.Group
}; // no ToArray
var results =
(from p in MyContext.tblPaySomething
join cae in MyContext.tblSomethingElse on p.PaymentCode equals cae.PaymentCode
join ca in MyContext.tblAnothThing on cae.SomeCode equals ca.SomeCode
join cg in MyContext.Codes.GroupBy(c => c.Code, c => c.Code) on cg.Key equals p.Code
where cg.Contains(ca.ContractCode.Value)
select new
{
p.ContractPeriodCode,
p.DomainSetExtensionCode,
p.IsFlagged,
p.Narrative,
p.PaymentCode,
ca.BookingCode,
cae.Status
})
.ToList();
Side Note: I also suggest using navigation properties where possible instead of joins. It makes it much easier to read and understand how objects are related and create complex queries.
I have this LINQ query:
var returnList = from TblItemEntity item in itemList
join TblClientEntity client in clientList
on item.ClientNo equals client.ClientNumber
join TblJobEntity job in jobList
on item.JobNo equals job.JobNo
where item.ClientNo == txtSearchBox.Text //Is this filter wrong?
orderby client.CompanyName
select new { FileId = item.FileId, CompanyName = client.CompanyName, LoanStatus = item.LoanStatus, JobNo = job.JobNo, JobFinancialYE = job.JobFinancialYE, VolumeNo = item.VolumeNo };
Why doesn't this return anything?
P/S : All of them are of string datatype.
Have you tried to remove parts of the join to figure out where the problem is and then add those removed parts back again one after one? Start with:
var returnList = from TblItemEntity item in itemList
where item.ClientNo == txtSearchBox.Text //Is this filter wrong?
select new { FileId = item.FileId };
Since you're doing inner joins there could be that one of the joins filters out all the items.
EDIT: When debugging don't expand the return type, the select new {FileId = item.FileId} is all you need to debug.
Still waiting on that sample data.
You say you're getting results filtering by other attributes so why should this be any different? Assuming the user-input txtSearchBox has a reasonable value, try printing the values out onto the debug console and see if you're getting reasonable results. Look at the output window. Try this version of your query:
Func<string,bool> equalsSearch = s =>
{
var res = s == txtSearchBox.Text;
Debug.WriteLine("\"{0}\" == \"{1}\" ({2})", s, txtSearchBox.Text, res);
return res;
};
var returnList = from TblItemEntity item in itemList
join TblClientEntity client in clientList
on item.ClientNo equals client.ClientNumber
join TblJobEntity job in jobList
on item.JobNo equals job.JobNo
//where item.ClientNo == txtSearchBox.Text //Is this filter wrong?
where equalsSearch(item.ClientNo) //use our debug filter
orderby client.CompanyName
select new { FileId = item.FileId, CompanyName = client.CompanyName, LoanStatus = item.LoanStatus, JobNo = job.JobNo, JobFinancialYE = job.JobFinancialYE, VolumeNo = item.VolumeNo };
Why doesn't this return anything?
There two possibilites:
1) The join is empty, that is, no items, clients and jobs have matching ID's.
2) The where clause is false for all records in the join.
To troubleshoot this you will have to remove the where clause and/or some of the joined tables to see what it takes to get any results.