I have a T-SQL Query that show Sum(TotalAmount) Sum(Discount) Sum(PayableAmount) from Table1 named p1 and show the Sum(PaidAmount) from Table2 named p2,
the tables p1 and p2 do not have any relationship with Forenkay and the primary key,
so I was not able to use the .net core method syntax _context.Table1.include(a=>a.table2) to join 2 tables because there is no relationship between these 2 tables,
So I have written the below code as T-SQL query and got the exact result that I wanted, but now I want to write the same T-SQL query as a LING query and use it inside my C#.net Core Controller code as query syntax or method syntax,
Here is my T-SQL Code that show Sum(TotalAmount) Sum(Discount) Sum(PayableAmount) from Table1 named p1 and show the Sum(PaidAmount) from Table2 named p2,
SELECT p1.PatientId,
SUM(p1.TotalAmount) as TotalTreatmentAmount,
SUM(p1.Discount) As TotalTreatmentDiscount,
SUM(p1.Payable) as TotalTreatmentPayable,
SUM(p1.Balance) as TotalTreatmentBalancce,
p2.TotalTreatmentPaidAmount
FROM PatientPayments as p1
join (SELECT p2.PatientId, SUM(p2.PaidAmount) as TotalTreatmentPaidAmount
FROM PatientPaymentHistories p2
where p2.PaymentType != 'Refund'
group by p2.PatientId) as p2
ON p2.PatientId = p1.PatientId
group by p1.PatientId, p2.TotalTreatmentPaidAmount
Here is my C# Code but this code does not work its wrong only the SQL code is working fine
public IActionResult ExportPatientPaymentDataToExcel()
{
var PatientPayments =
from p1 in _context.PatientPayments
join p2 in _context.PatientPaymentHistories on p1.PatientId equals p2.PatientId
select new
{
p1.PatientId,
p1.TotalAmount,
p1.Discount,
p1.Payable,
p2.PaidAmount
};
DataTable PatientPaymentTable = new DataTable("PatientPayment");
PatientPaymentTable.Columns.AddRange(new DataColumn[5]
{
new DataColumn("Patient ID"),
new DataColumn("Total Amount"),
new DataColumn("Total Discount"),
new DataColumn("Total Payable"),
new DataColumn("Total Paid"),
});
foreach (var PatientPayment in PatientPayments)
{
PatientPaymentTable.Rows.Add(
PatientPayment.PatientId,
PatientPayment.TotalAmount,
PatientPayment.Discount,
PatientPayment.Payable,
PatientPayment.PaidAmount
);
}
using (XLWorkbook wb = new XLWorkbook())
{
wb.Worksheets.Add(PatientPaymentTable);
using (MemoryStream stream = new MemoryStream())
{
wb.SaveAs(stream);
return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", GetLocalDateTime().Date.ToShortDateString() + " " + "PatientPayment_Data.xlsx");
}
}
}
Please help me to change the above T-SQL Code to C# Ling query
This should work as expected:
var query = _context.PatientPayments.Join(_context.PatientPaymentHistories
.Where(x => x.Type != "Refund")
.GroupBy(x => x.PatientId)
.Select(x => new
{
PatientId = x.Key,
TotalTreatmentPaidAmount = x.Sum(y => y.PaidAmount)
}),
x => x.PatientId,
y => y.PatientId,
(x, y) => new
{
PatientId = x.PatientId,
TotalAmount = x.TotalAmount,
Discount = x.Discount,
Payable = x.Payable,
Balance = x.Balance,
TotalTreatmentPaidAmount = y.TotalTreatmentPaidAmount
})
.GroupBy(x => new { PatientId = x.PatientId,
TotalTreatmentPaidAmount = x.TotalTreatmentPaidAmount })
.Select(x => new
{
PatientId = x.Key.PatientId,
TotalTreatmentAmount = x.Sum(y => y.TotalAmount),
TotalTreatmentDiscount = x.Sum(y => y.Discount),
TotalTreatmentPayable = x.Sum(y => y.Payable),
TotalTreatmentBalancce = x.Sum(y => y.Balance),
TotalTreatmentPaidAmount = x.Key.TotalTreatmentPaidAmount
});
Based on your T-SQL, try it like this
var query = _context.PatientPayments
.Join(_context.PatientPaymentHistories
.Where(s => s.PaymentType != 'Refund')
.GroupBy(p => p.PatientId)
.Select(g => select new {
PatientId = g.Key,
TotalTreatmentPaidAmount = g.Sum(x => x.PaidAmount)
}),
p1 => p1.PatientId,
p2 => p2.PatientId,
(p1, p2) => new { PatientPayments = p1, PatientPaymentHistories = p2 })
.GroupBy(s => new { s.PatientPayments.PatientId, s.PatientsPaymentHistories.TotalTreatmentPaidAmount })
.Select(gs => new
{
gs.Key.PatientId,
TotalTreatmentAmount = gs.Sum(x => x.PatientPayments.TotalAmount),
TotalTreatmentDiscount = gs.Sum(x => x.PatientPayments.Discount),
TotalTreatmentPayable = gs.Sum(x => x.PatientPayments.Payable),
TotalTreatmentBalancce = gs.Sum(x => x.PatientPayments.Balance),
gs.Key.TotalTreatmentPaidAmount
};
Related
I've been searching for a while now. But all the solutions seems to be different than what I expect.
So this is my query in SQL:-
Select * from
(
select Name,Description Descr from CourseTbl
union all
select MainDesc Name,MainDesc Descr from CoursedescTbl
union all
select SubHeading Name,SubDesc Descr from CourseSubDesc
union all
select Name,Descr as Descr from InternTbl
)A where A.Name like '%D%' or A.Descr like '%D%'
I want to execute the above query using LINQ or EF. and return the list in Json format. So I tried many failed attempts and this is one of them:-
public JsonResult SearchDetail()
{
string SearchKey = Request.Form["SearchName"].ToString();
IEnumerable<SearchList> QueryResult;
using (EBContext db = new EBContext())
{
try
{
QueryResult =
(from x in db.Courses
select new { A = x.Name, B = x.Description })
.Concat(from y in db.CourseDesc
select new { A = y.MainHeading, B = y.MainDesc })
.Concat(from z in db.CourseSubDesc
select new { A = z.SubDesc, B = z.SubHeading })
.Concat(from w in db.Interns
select new { A = w.Name, B = w.Descr })
.ToList();
}
catch (Exception ex)
{
return new JsonResult
{
Data = ex.Message,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
return new JsonResult
{
Data = QueryResult,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
And my SearchList Class is like this:-
public class SearchList
{
public string Name { get; set; }
public string Descr { get; set; }
}
I'm not able to put the where clause in linq query which will search in all table.
I'm getting error when I assign queryresult to my ef query. It says cannot cast to Innumerable.
Thanks in Advance.
Could you explain more on the error you are getting?
Also, have you tried using .Union() in linq?
QueryResult = db.Courses.Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
.ToList(); //this isn't necessary
Edit: There are two ways to input where clause, either with each search, or at the end:
QueryResult = db.Courses.Where(x=>x.Name == "Name").Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Where(y=>y.MainHeading == "Name").Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
.ToList();
Or:
QueryResult = db.Courses.Where(x=>x.Name == "Name").Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Where(y=>y.MainHeading == "Name").Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
//Where can go either before or after .ToList
.Where(item=>item.A == "Name")
.ToList();
You did not say what error/exception you are getting. But your QueryResult is of type IEnumerable<SearchList> and you appear to be assigning it an enumerable of anonymous type { A, B }.
Try this:
QueryResult = (from x in db.Courses
select new SearchList { Name = x.Name, Descr = x.Description })
.Concat(...)
.ToList();
Or
QueryResult = db.Courses.Select(x => new SearchList
{ Name = x.Name, Descr = x.Description})
.Concat(...)
.ToList();
UPDATE
Your #2 issue will be fixed if you changed your select to new up a SearchList as I did above, instead of new-ing an anonymous type.
As for your issue #1, you should insert the Where() before your Select():
result1 = db.Courses
.Where(x => x.Name.Contains('D') || x.Description.Contains('D'))
.Select(x => new SearchList { Name = x.Name, Descr = x.Description});
result2 = db.CourseDesc
.Where(y => y.MainHeading.Contains('D') || y.MainDesc.Contains('D'))
.Select(y => new SearchList { Name = y.MainHeading, Descr = y.MainDesc});
result3 = db.CourseSubDesc
.Where(...)
.Select(...);
QueryResult = result1.Concat(result2).Concat(result3).ToList();
Doing Where() as part of the query on each table is important so you do not fetch all records from that table, unlike if you do the Where() after Concat(). Also note that Concat() may throw an ArgumentNullException.
Take the lists Separately and query and concat
check this example
List<string> a = new List<string>() { "a", "b", "c" };
List<string> b = new List<string>() { "ab", "bb", "cb" };
IEnumerable<SearchList> QueryResult =
a.Where(x => x.Contains("a")).Select(x => new SearchList() { Name = x, Descr = x })
.Concat(b.Where(x => x.Contains("a")).Select(x => new SearchList() { Name = x, Descr = x }));
I have a problem in group by with link to sql
first I have this tables :
client : Id_client , nom , prenom , villeId
ville: id_ville , nom
Code:
justiceDataContext dbContext = new justiceDataContext();
GridView1.DataSource = from client in dbContext.Client
join ville in dbContext.Commande
on client.villeId equals ville.Id_ville
group client by ville.nom into g
select new { City = g.Key, NumberOfClients = g.Count() };
GridView1.DataBind();
My objective is to get number of client by city (ville)
thank you
dbContext.Client
.GroupBy(c => c.villeId)
.Select(g => new {
CityName = dbContext.Villes.Where(v => v.Id_ville == g.Key),
NumberOfClient = g.Count()
}).ToList();
Another approach:
var result = dbContext.Villes
.Join(dbContextClients, v => v.IdVille, c => c.IdVille, (v, c) => new { client = c, ville = v })
.GroupBy(j => j.ville.IdVille)
.Select(g => new {
VilleName = g.First().ville.Name,
NumberOfClients = g.Count()
}).ToList();
im pretty new to linq-lambda. I have a MySQL query that pulls the name of items in two tables union'd together. Then pull another column of the specialties that the items fall under.
my working query is this:
Select
p.title,
GROUP_CONCAT(spec.categoryname) genre
From
(SELECT FullName AS title, TypeId as typeid, Id as id FROM programs
UNION
SELECT FullName, TypeId, Id FROM products)
AS p
Inner join specialtymembers mem on (ItemType = p.typeid AND ItemId = p.id)
Inner join specialties spec on mem.Category = spec.id
GROUP BY p.title
ORDER BY p.title
now my problem is... that i have to somehow convert this into linq lambda. My attempt is this:
var allitems =
_programContentService.Products.Select(r => r.FullName)
.Union(_programContentService.Programs.Select(q => q.FullName))
.Join(_programContentService.SpecialtyMembers, z => z.ItemType, q => q.ItemType,
(z, q) => new {z, q})
.Join(_programContentService.Specialties, x => x.Id, z => z.Category,
(x, z) => new {x,z})
.Select(#t => new SelectListItem { Name = q.FillName.ToString(), Genre = "SOME HOW HAVE TO USE A LOOPING FEATURE??" });
UPDATE:
var allitems = _programContentService
.ProgramProductViews
.Select(x => new {x.FullName, x.TypeId, x.Id})
.Join(
_programContentService.SpecialtyMembers,
type => new {type.TypeId, type.Id},
member => new {TypeId = member.ItemType, Id = member.ItemId},
(type, member) => new {type.FullName, member.Category})
.Join(
_programContentService.Specialties,
q => q.Category,
specialty => specialty.Id,
(q, specialty) => new { q.FullName, specialty.SpecialtyName })
.GroupBy(x=>x.FullName)
.AsEnumerable()
.Select(x => new SelectListItem
{
Value = x.Key,
Text = String.Join(",", x.Select(q=>q.SpecialtyName))
});
i have a feeling that I am close...
I think this will get you what you want. It is untested, if you have issues let me know and I will work it out.
var allitems =
_programContentService
.Products
.Select(x => new { x.FullName, x.TypeId, x.Id })
.Union(
_programContentService
.Programs
.Select(x => new { x.FullName, x.TypeId, x.Id }))
.Join(
_programContentService.SpecialtyMembers,
type => new { type.TypeId, type.Id },
member => new { TypeId = member.ItemType, Id = member.ItemId },
(type, member) => new { type.FullName, member.Category })
.Join(
_programContentService.Specialties,
x => x.Category,
specialty => specialty.Id,
(x, specialty) => new { x.FullName, specialty.CategoryName })
.GroupBy(x => x.FullName)
.AsEnumerable()
.Select(x => new SelectListItem
{
Value = x.Key,
Text = String.Join(",", x.Select(y => y.CategoryName))
});
var residenceRep =
ctx.ShiftEmployees
.Include(s => s.UserData.NAME)
.Include(s => s.ResidenceShift.shiftName)
.Join(ctx.calc,
sh => new { sh.empNum, sh.dayDate },
o => new { empNum = o.emp_num, dayDate = o.trans_date },
(sh, o) => new { sh, o })
.Where(s => s.sh.recordId == recordId && s.o.day_flag.Contains("R1"))
.OrderBy(r => r.sh.dayDate)
.Select(r => new
{
dayDate = r.sh.dayDate,
empNum = r.sh.empNum,
empName = r.sh.UserData.NAME,
shiftId = r.sh.shiftId,
shiftName = r.sh.ResidenceShift.shiftName,
recordId,
dayState = r.o.day_desc.Split('[', ']')[1]
}).ToList();
I get an exception :
The LINQ expression node type 'ArrayIndex' is not supported in LINQ to
Entities
How i could find an alternative to Split('[', ']')[1] in this query
You must commit the query and do the split after loading the data:
var residenceRep =
ctx.ShiftEmployees
.Include(s => s.UserData.NAME)
.Include(s => s.ResidenceShift.shiftName)
.Join(ctx.calc,
sh => new { sh.empNum, sh.dayDate },
o => new { empNum = o.emp_num, dayDate = o.trans_date },
(sh, o) => new { sh, o })
.Where(s => s.sh.recordId == recordId && s.o.day_flag.Contains("R1"))
.OrderBy(r => r.sh.dayDate)
.Select(r => new
{
dayDate = r.sh.dayDate,
empNum = r.sh.empNum,
empName = r.sh.UserData.NAME,
shiftId = r.sh.shiftId,
shiftName = r.sh.ResidenceShift.shiftName,
recordId = r.sh.recordId,
dayState = r.o.day_desc,
})
.ToList()//Here we commit the query and load data
.Select(x=> {
var parts = x.dayState.Split('[', ']');
return new {
x.dayDate,
x.empNum,
x.empName,
x.shiftId,
x.shiftName,
x.recordId,
dayState = parts.Length > 1 ?parts[1]:"",
};
})
.ToList();
I had this Issue and the approach that I've chose was that get all element I wanted and save them into a List and then filter the actual data on that list.
I know this is not the best answer but it worked for me.
How can I do GroupBy multiple columns in LINQ
Something similar to this in SQL:
SELECT * FROM <TableName> GROUP BY <Column1>,<Column2>
How can I convert this to LINQ:
QuantityBreakdown
(
MaterialID int,
ProductID int,
Quantity float
)
INSERT INTO #QuantityBreakdown (MaterialID, ProductID, Quantity)
SELECT MaterialID, ProductID, SUM(Quantity)
FROM #Transactions
GROUP BY MaterialID, ProductID
Use an anonymous type.
Eg
group x by new { x.Column1, x.Column2 }
Procedural sample:
.GroupBy(x => new { x.Column1, x.Column2 })
Ok got this as:
var query = (from t in Transactions
group t by new {t.MaterialID, t.ProductID}
into grp
select new
{
grp.Key.MaterialID,
grp.Key.ProductID,
Quantity = grp.Sum(t => t.Quantity)
}).ToList();
For Group By Multiple Columns, Try this instead...
GroupBy(x=> new { x.Column1, x.Column2 }, (key, group) => new
{
Key1 = key.Column1,
Key2 = key.Column2,
Result = group.ToList()
});
Same way you can add Column3, Column4 etc.
Since C# 7 you can also use value tuples:
group x by (x.Column1, x.Column2)
or
.GroupBy(x => (x.Column1, x.Column2))
C# 7.1 or greater using Tuples and Inferred tuple element names (currently it works only with linq to objects and it is not supported when expression trees are required e.g. someIQueryable.GroupBy(...). Github issue):
// declarative query syntax
var result =
from x in inMemoryTable
group x by (x.Column1, x.Column2) into g
select (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity));
// or method syntax
var result2 = inMemoryTable.GroupBy(x => (x.Column1, x.Column2))
.Select(g => (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity)));
C# 3 or greater using anonymous types:
// declarative query syntax
var result3 =
from x in table
group x by new { x.Column1, x.Column2 } into g
select new { g.Key.Column1, g.Key.Column2, QuantitySum = g.Sum(x => x.Quantity) };
// or method syntax
var result4 = table.GroupBy(x => new { x.Column1, x.Column2 })
.Select(g =>
new { g.Key.Column1, g.Key.Column2 , QuantitySum= g.Sum(x => x.Quantity) });
You can also use a Tuple<> for a strongly-typed grouping.
from grouping in list.GroupBy(x => new Tuple<string,string,string>(x.Person.LastName,x.Person.FirstName,x.Person.MiddleName))
select new SummaryItem
{
LastName = grouping.Key.Item1,
FirstName = grouping.Key.Item2,
MiddleName = grouping.Key.Item3,
DayCount = grouping.Count(),
AmountBilled = grouping.Sum(x => x.Rate),
}
Though this question is asking about group by class properties, if you want to group by multiple columns against a ADO object (like a DataTable), you have to assign your "new" items to variables:
EnumerableRowCollection<DataRow> ClientProfiles = CurrentProfiles.AsEnumerable()
.Where(x => CheckProfileTypes.Contains(x.Field<object>(ProfileTypeField).ToString()));
// do other stuff, then check for dups...
var Dups = ClientProfiles.AsParallel()
.GroupBy(x => new { InterfaceID = x.Field<object>(InterfaceField).ToString(), ProfileType = x.Field<object>(ProfileTypeField).ToString() })
.Where(z => z.Count() > 1)
.Select(z => z);
var Results= query.GroupBy(f => new { /* add members here */ });
A thing to note is that you need to send in an object for Lambda expressions and can't use an instance for a class.
Example:
public class Key
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
This will compile but will generate one key per cycle.
var groupedCycles = cycles.GroupBy(x => new Key
{
Prop1 = x.Column1,
Prop2 = x.Column2
})
If you wan't to name the key properties and then retreive them you can do it like this instead. This will GroupBy correctly and give you the key properties.
var groupedCycles = cycles.GroupBy(x => new
{
Prop1 = x.Column1,
Prop2= x.Column2
})
foreach (var groupedCycle in groupedCycles)
{
var key = new Key();
key.Prop1 = groupedCycle.Key.Prop1;
key.Prop2 = groupedCycle.Key.Prop2;
}
group x by new { x.Col, x.Col}
.GroupBy(x => (x.MaterialID, x.ProductID))
.GroupBy(x => x.Column1 + " " + x.Column2)
For VB and anonymous/lambda:
query.GroupBy(Function(x) New With {Key x.Field1, Key x.Field2, Key x.FieldN })