Linq Group on Multiple Fields - VB.NET, Anonymous, Key - vb.net

I am stumped. I need help. I have a DTO object with duplicates patient address data. I need to get only the unique addresses.
Dim PatientAddressDto = New List(Of PatientAddress)
{Populate PatientAddressDto with lots of duplicate data}
PatientAddressDto = (From d In PatientAddressDto
Group d By PatientAddressDtoGrouped = New PatientAddress With {
.Address1 = d.Address1,
.Address2 = d.Address2,
.City = d.City,
.State = d.State,
.Zip = d.Zip
}
Into Group
Select New PatientAddress With {
.Address1 = PatientAddressDtoGrouped.Address1,
.Address2 = PatientAddressDtoGrouped.Address2,
.City = PatientAddressDtoGrouped.City,
.State = PatientAddressDtoGrouped.State,
.Zip = PatientAddressDtoGrouped.Zip
}).ToList()
I have tried the following with no luck:
PatientAddressDto = (From d In PatientAddressDto
Select New PatientAddress With {
.Address1 = d.Address1,
.Address2 = d.Address2,
.City = d.City,
.State = d.State,
.Zip = d.Zip
}).Distinct
and also
PatientAddressDto = PatientAddressDto.GroupBy(Function(p) New PatientAddress With {
.Address1 = p.Address1,
.Address2 = p.Address2,
.City = p.City,
.State = p.State,
.Zip = p.Zip
})

You can use an anonymous type and make use of the Key keyword in order for equality to behave the way you expect (not required for C#).
Change your grouping by specifying the Key prefix and remove the PatientAddress usage :
Group d By PatientAddressDtoGrouped = New With {
Key .Address1 = d.Address1,
Key .Address2 = d.Address2,
Key .City = d.City,
Key .State = d.State,
Key .Zip = d.Zip
}

I have found the following code to work which essentially accomplishes the grouping that I desire and populating the new object as type PatientAddress therefore eliminating the use of anonymous objects and the keyword Key.
Maybe someone can explain it, at the moment I can not. Have a nice day.
Dim PatientAddressDto = New List(Of PatientAddress)
{Populate PatientAddressDto with lots of duplicate data}
PatientAddressDto = (From d In PatientAddressDto
Group d By d.Address1,
d.Address2,
d.City,
d.State,
d.Zip Into g =
Group Let grp = New PatientAddress With {.Address1 = Address1,
.Address2 = Address2,
.City = City,
.State = State,
.Zip = Zip}
Select grp).ToList()

Its probably because PatientAddress does not override GetHashCode and Equals.
An alternative is to us an anonymous type for the grouping. Try writing:
Group d By PatientAddressDtoGrouped = New With { Key .Address1 = d.Address1, ....

Related

Using LINQ to Entity - How can I join/concatenate columns from another table

I am having some issues with trying to figure out the correct way, or syntax, to join/concatenate a series of "name" columns from a separate table into a query.
Currently I am testing in LINQpad using two queries; the first returns all the master data that I use for other background work, and the second is a user-friendly version that I bind to a DGV. The issue comes in when I try to join the Physicians names like I do for a separate combobox.
This is what I have thus far - while it does return the Physician's name, it will NOT return the name if the TITLE field is NULL on the Physicians table.
Dim query1 = (From demog In data_Demogs
From MedHist In data_Demog_MedHists.where(Function(a) demog.ID_Demog = a.ID_Demog).defaultifempty
From BGLAssay In data_Demog_BGLs.where(Function(a) demog.ID_Demog = a.ID_Demog).defaultifempty
Select
demog.ID_Demog,
demog.Last_Name,
demog.First_Name,
demog.ID_Demog_AKA,
demog.DOB,
demog.Gender,
demog.ST_Complete,
demog.LT_Complete,
demog.LT_Due_Date,
demog.ID_Physician,
demog.ID_Reason_For_Call,
demog.Intl_Patient,
demog.Mayo_Patient,
MedHist.ID_Disease_Group,
MedHist.ID_Disease_Type,
BGLAssay.ID_BGL_Assay)
Dim query2 = (From items In query1
From demogAKA In data_Demogs.Where(Function(a) items.ID_Demog = a.ID_Demog_AKA).defaultifempty
From DType In tbl_Disease_Types.Where(Function(a) items.ID_Disease_Type = a.ID_Disease_Type).defaultifempty
From DGroup In tbl_Disease_Groups.Where(Function(a) items.ID_Disease_Group = a.ID_Disease_Group).defaultifempty
From RFC In tbl_Reason_For_Calls.Where(Function(a) items.ID_Reason_For_Call = a.ID_Reason_For_Call).defaultifempty
From Phys In tbl_Physicians.Where(Function(a) items.ID_Physician = a.ID_Physician).defaultifempty
From Title In tbl_Titles.Where(Function(a) Phys.ID_Title = a.ID_Title).defaultifempty
Select
items.ID_Demog,
items.Last_Name,
items.First_Name,
AKA_Name = demogAKA.Last_Name + ", " + demogAKA.First_Name,
items.DOB,
items.Gender,
items.ST_Complete,
items.LT_Complete,
items.LT_Due_Date,
DType.Disease_Type_Abr,
DGroup.Disease_Group_Name,
RFC.Reason_For_Call,
items.ID_Physician,
Phys_Name = Phys.Last_Name + ", " + Phys.First_Name + ", " + Title.Title
).distinct
console.writeline(Query2)
This is the currently query I for a combobox that DOES bring back all names, joining those names even if a field is NULL.
Dim Phys = (From e In tbl_Physicians
Group Join f In tbl_Titles On e.ID_Title Equals f.ID_Title
Into Matched = Group
From m In Matched.DefaultIfEmpty()
Select e.ID_Physician,
e.Last_Name,
e.First_Name,
e.Middle_Initial,
m.Title
).ToArray().Select(Function(item) New With {
.ID = item.ID_Physician,
.Phys_Name = (String.Join(", ",
String.Join(",",
New String() {item.Last_Name, item.First_Name, item.Title}).Split(
New Char() {","}, System.StringSplitOptions.RemoveEmptyEntries)))
})
Console.writeline(Phys)
When I try to add a third query to return just the Physician's name, and join that to the final query, I get the following error:
Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator.
'Query 1 removed to save space
Dim PhysNames = (From e In tbl_Physicians
Group Join f In tbl_Titles On e.ID_Title Equals f.ID_Title
Into Matched = Group
From m In Matched.DefaultIfEmpty()
Select e.ID_Physician,
e.Last_Name,
e.First_Name,
e.Middle_Initial,
m.Title
).ToArray().Select(Function(item) New With {
.ID = item.ID_Physician,
.Phys_Name = (String.Join(", ",
String.Join(",",
New String() {item.Last_Name, item.First_Name, item.Title}).Split(
New Char() {","}, System.StringSplitOptions.RemoveEmptyEntries)))
})
Dim query2 = (From items In query1
From demogAKA In data_Demogs.Where(Function(a) items.ID_Demog = a.ID_Demog_AKA).defaultifempty
From DType In tbl_Disease_Types.Where(Function(a) items.ID_Disease_Type = a.ID_Disease_Type).defaultifempty
From DGroup In tbl_Disease_Groups.Where(Function(a) items.ID_Disease_Group = a.ID_Disease_Group).defaultifempty
From RFC In tbl_Reason_For_Calls.Where(Function(a) items.ID_Reason_For_Call = a.ID_Reason_For_Call).defaultifempty
From Phys In PhysNames.Where(Function(a) items.ID_Physician = a.ID).defaultifempty
Select
items.ID_Demog,
items.Last_Name,
items.First_Name,
AKA_Name = demogAKA.Last_Name + ", " + demogAKA.First_Name,
items.DOB,
items.Gender,
items.ST_Complete,
items.LT_Complete,
items.LT_Due_Date,
DType.Disease_Type_Abr,
DGroup.Disease_Group_Name,
RFC.Reason_For_Call,
items.ID_Physician,
Phys.Phys_Name
).distinct
console.writeline(Query2)
When I try to join my working query into the final query, I get the following error:
Invalid cast from 'System.String' to 'VB$AnonymousDelegate_0`2[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934...
'Query1 removed to save space
Dim query2 = (From items In query1
From demogAKA In data_Demogs.Where(Function(a) items.ID_Demog = a.ID_Demog_AKA).defaultifempty
From DType In tbl_Disease_Types.Where(Function(a) items.ID_Disease_Type = a.ID_Disease_Type).defaultifempty
From DGroup In tbl_Disease_Groups.Where(Function(a) items.ID_Disease_Group = a.ID_Disease_Group).defaultifempty
From RFC In tbl_Reason_For_Calls.Where(Function(a) items.ID_Reason_For_Call = a.ID_Reason_For_Call).defaultifempty
From Phys In tbl_Physicians
Where items.ID_Physician = Phys.ID_Physician
Group Join f In tbl_Titles On Phys.ID_Title Equals f.ID_Title
Into Matched = Group
From m In Matched.DefaultIfEmpty()
Select
items.ID_Demog,
items.Last_Name,
items.First_Name,
AKA_Name = demogAKA.Last_Name + ", " + demogAKA.First_Name,
items.DOB,
items.Gender,
items.ST_Complete,
items.LT_Complete,
items.LT_Due_Date,
DType.Disease_Type_Abr,
DGroup.Disease_Group_Name,
RFC.Reason_For_Call,
items.ID_Physician,
PhysName = Function(a) String.Join(", ",
String.Join(",",
New String() {Phys.Last_Name, Phys.First_Name, m.Title}).Split(
New Char() {","}, System.StringSplitOptions.RemoveEmptyEntries))
).distinct
console.writeline(Query2)
After a long time playing around in LINQpad, and then finally re-reading JM's answer to a former question I had, I realized what I was doing wrong.
As per his post:
The problem is that, while LINQ in general has no issue with that code, LINQ to Entities does. LINQ syntax is the same for every provider but the implementation under the hood differs and, in the case of LINQ to Entities, your LINQ code has to translated to SQL and, in this case, there's no mapping from String.Join to SQL. That code would work fine with LINQ to Objects so one solution is to push that operation out of the original query and into a LINQ to Objects query. That would mean selecting the raw data with your LINQ to Entities query, calling ToList or ToArray on the result to materialise the query, then performing another query on that result. That second query will be LINQ to Objects rather than LINQ to Entities and so String.Join will not be an issue.
So... Once I realized I needed to push out the String.Join, I ended up with the following code:
Dim DispList = (From items In MastList
From demogAKA In dbACL.data_Demog.Where(Function(a) items.ID_Demog = a.ID_Demog_AKA).DefaultIfEmpty
From DType In dbACL.tbl_Disease_Type.Where(Function(a) items.ID_Disease_Type = a.ID_Disease_Type).DefaultIfEmpty
From DGroup In dbACL.tbl_Disease_Group.Where(Function(a) items.ID_Disease_Group = a.ID_Disease_Group).DefaultIfEmpty
From RFC In dbACL.tbl_Reason_For_Call.Where(Function(a) items.ID_Reason_For_Call = a.ID_Reason_For_Call).DefaultIfEmpty
From e In dbACL.tbl_Physician.Where(Function(a) items.ID_Physician = a.ID_Physician).DefaultIfEmpty
Group Join f In dbACL.tbl_Title On e.ID_Title Equals f.ID_Title
Into Matched = Group
From m In Matched.DefaultIfEmpty()
Select
items.ID_Demog,
items.Last_Name,
items.First_Name,
AKALname = demogAKA.Last_Name,
AKAFname = demogAKA.First_Name,
items.DOB,
items.Gender,
items.ST_Complete,
items.LT_Complete,
items.LT_Due_Date,
DType.Disease_Type_Abr,
DGroup.Disease_Group_Name,
RFC.Reason_For_Call,
items.ID_Physician,
PLName = e.Last_Name,
PFname = e.First_Name,
PMI = e.Middle_Initial,
PTitle = m.Title
).Distinct.ToList().Select(Function(a) New With {
a.ID_Demog,
a.Last_Name,
a.First_Name,
.AKA_Name = (String.Join(", ",
String.Join(",",
New String() {a.AKALname, a.AKAFname}).Split(
New Char() {","}, System.StringSplitOptions.RemoveEmptyEntries))),
a.DOB,
a.Gender,
a.ST_Complete,
a.LT_Complete,
a.LT_Due_Date,
a.Disease_Type_Abr,
a.Disease_Group_Name,
a.Reason_For_Call,
a.ID_Physician,
.PName = (String.Join(", ",
String.Join(",",
New String() {a.PLName, a.PFname, a.PTitle}).Split(
New Char() {","}, System.StringSplitOptions.RemoveEmptyEntries)))
}).ToList()

EF query hits database more than one time

maybe is a simple issue but I'm pretty new to EF so:
I have this query:
Dim InvoicesQuery = (From i As Invoice In dbContext.Invoices.AsNoTracking() Where i.InvoiceNumber = -1
Select New InvoicesWithDetails With {
.InvoiceDetails = i.InvoicesDetails,
.InvoiceDetailsUnmerged = i.InvoicesDetailsUnmergeds,
.Examination = Nothing,
.Applicant = Nothing,
.InvoiceNumber = i.InvoiceNumber,
.InvoiceYear = i.InvoiceYear,
.DocCode = i.DocCode,
.CompanyId = i.CompanyId,
.InvoiceDate = i.InvoiceDate,
.NetAmount = i.NetAmount,
.AmountPaid = i.AmountPaid,
.AmountToPay = i.AmountToPay,
.VAT = i.VAT,
.AdditionalTax = i.AdditionalTax,
.Status = i.Status,
.Amount = i.Amount,
.ExaminationId = i.ExaminationId,
.ReceiverName = If(i.OtherReceiverName Is Nothing, i.ReceiverName, i.OtherReceiverName),
.ReceiverAddress = If(i.OtherReceiverAddress Is Nothing, i.ReceiverAddress, i.OtherReceiverAddress),
.ReceiverCity = If(i.OtherReceiverCity Is Nothing, i.ReceiverCity, i.OtherReceiverCity),
.ReceiverTaxCode = If(i.OtherReceiverTaxCode Is Nothing, i.ReceiverTaxCode, i.OtherReceiverTaxCode),
.ReceiverCompanyTaxCode = i.ReceiverCompanyTaxCode,
.ReceiverZipCode = If(i.OtherReceiverZipCode Is Nothing, i.ReceiverZipCode, i.OtherReceiverZipCode),
.IsCreditNote = i.IsCreditNote,
.HasCreditNote = i.HasCreditNote,
.FixedAdditionalAmountOnInvoice = i.FixedAdditionalAmountOnInvoice,
.CashFlowPaymentModeId = If(i.CashFlowPaymentModeId IsNot Nothing, i.CashFlowPaymentModeId.Trim, Nothing),
.AgreementDeductible = i.AgreementDeductible,
.IsPatientInvoiceRecipient = i.IsPatientInvoiceRecipient,
.IsApplicantInvoiceRecipient = i.IsApplicantInvoiceRecipient,
.IsDoctorInvoiceRecipient = i.IsDoctorInvoiceRecipient,
.DoctorId = If(i.DoctorId IsNot Nothing, i.DoctorId, Nothing),
.Doctor = Nothing,
.CreditNoteParentInvoice = i.CreditNoteParentInvoice,
.CreditNoteParentInvoiceYear = i.CreditNoteParentInvoiceYear,
.IsDeferredInvoice = i.IsDeferredInvoice,
.IsExtracted = If(i.IsExtracted IsNot Nothing, i.IsExtracted, False),
.IsExportedToHOST = If(i.IsExportedToHOST IsNot Nothing, i.IsExportedToHOST, False),
.ApplicantId = i.ApplicantId,
.InvoiceHasVAT = i.InvoiceHasVAT,
.VAT_Percentage = i.VAT_Percentage,
.IssuedBy = i.IssuedBy,
.MaskedCounter = i.MaskedCounter,
.DocTypeId = i.DocTypeId,
.OtherReceiverName = i.OtherReceiverName,
.OtherReceiverAddress = i.OtherReceiverAddress,
.OtherReceiverCity = i.OtherReceiverCity,
.OtherReceiverTaxCode = i.OtherReceiverTaxCode,
.OtherReceiverZipCode = i.OtherReceiverZipCode,
.CashFlows = i.CashFlows}).ToList
InvoicesWithDetails is a class that hinerits Invoice; Invoice is a db entity
After this call I loop through the results like this:
For Each i As InvoicesWithDetails In InvoicesQuery.Where(Function(iwd) iwd.CompanyDescription Is Nothing And iwd.CompanyId IsNot Nothing)
i.CompanyDescription = ReturnCompanyDescription(i.CompanyId)
Next
For each cycle in the loop the database is called.
I thought that after the .ToList in the first call I could iterate the results without invoke the database.
What is wrong?
Thanks in advance
Ok, I worked more on that and I tried a different approach:
This is the new query, targeting the Invoice entity:
Dim InvoicesQuery As List(Of Invoice)
InvoicesQuery = (From i As Invoice In dbContext.Invoices.AsNoTracking Where
i.InvoiceDate >= FromDate And i.InvoiceDate <= ToDate).ToList
After that I create a new istance of InvoiceWithDetails and set all the properties like this:
For Each i As Invoice In InvoicesQuery
Dim newInvoiceWithDetails As New InvoicesWithDetails
With newInvoiceWithDetails
.InvoiceDetails = i.InvoicesDetails
.InvoiceDetailsUnmerged = i.InvoicesDetailsUnmergeds
.Examination = Nothing
.Applicant = Nothing
.InvoiceNumber = i.InvoiceNumber
.InvoiceYear = i.InvoiceYear
.DocCode = i.DocCode
.CompanyId = i.CompanyId
.InvoiceDate = i.InvoiceDate
.NetAmount = i.NetAmount
.AmountPaid = i.AmountPaid
.AmountToPay = i.AmountToPay
.VAT = i.VAT
.AdditionalTax = i.AdditionalTax
.Status = i.Status
.Amount = i.Amount
.ExaminationId = i.ExaminationId
.ReceiverName = If(i.OtherReceiverName Is Nothing, i.ReceiverName, i.OtherReceiverName)
.ReceiverAddress = If(i.OtherReceiverAddress Is Nothing, i.ReceiverAddress, i.OtherReceiverAddress)
.ReceiverCity = If(i.OtherReceiverCity Is Nothing, i.ReceiverCity, i.OtherReceiverCity)
.ReceiverTaxCode = If(i.OtherReceiverTaxCode Is Nothing, i.ReceiverTaxCode, i.OtherReceiverTaxCode)
.ReceiverCompanyTaxCode = i.ReceiverCompanyTaxCode
.ReceiverZipCode = If(i.OtherReceiverZipCode Is Nothing, i.ReceiverZipCode, i.OtherReceiverZipCode)
.IsCreditNote = i.IsCreditNote
.HasCreditNote = i.HasCreditNote
.FixedAdditionalAmountOnInvoice = i.FixedAdditionalAmountOnInvoice
.CashFlowPaymentModeId = If(i.CashFlowPaymentModeId IsNot Nothing, i.CashFlowPaymentModeId.Trim, Nothing)
.AgreementDeductible = i.AgreementDeductible
.IsPatientInvoiceRecipient = i.IsPatientInvoiceRecipient
.IsApplicantInvoiceRecipient = i.IsApplicantInvoiceRecipient
.IsDoctorInvoiceRecipient = i.IsDoctorInvoiceRecipient
.DoctorId = If(i.DoctorId IsNot Nothing, i.DoctorId, Nothing)
.Doctor = Nothing
.CreditNoteParentInvoice = i.CreditNoteParentInvoice
.CreditNoteParentInvoiceYear = i.CreditNoteParentInvoiceYear
.IsDeferredInvoice = i.IsDeferredInvoice
.IsExtracted = If(i.IsExtracted IsNot Nothing, i.IsExtracted, False)
.IsExportedToHOST = If(i.IsExportedToHOST IsNot Nothing, i.IsExportedToHOST, False)
.ApplicantId = i.ApplicantId
.InvoiceHasVAT = i.InvoiceHasVAT
.VAT_Percentage = i.VAT_Percentage
.IssuedBy = i.IssuedBy
.MaskedCounter = i.MaskedCounter
.DocTypeId = i.DocTypeId
.OtherReceiverName = i.OtherReceiverName
.OtherReceiverAddress = i.OtherReceiverAddress
.OtherReceiverCity = i.OtherReceiverCity
.OtherReceiverTaxCode = i.OtherReceiverTaxCode
.OtherReceiverZipCode = i.OtherReceiverZipCode
.CashFlows = i.CashFlows
End With
FinalList.Add(newInvoiceWithDetails)
For each cycle and each property value, the database is invoked
Again, what is wrong?

Linq2Db / Access - error with anonymous group by multiple fields

I have 2 tables: pob (with results of some activities) and names (with user data). I try to select top 5 users from table pob based on their last activity date. So I inner join names and pob, then select top 5 users based on calculated max(date).
This query is working:
SELECT TOP 5
[u].[id],
[u].[name],
max([p].[date]) As LastDateOfUse,
FROM
[pob] [p]
INNER JOIN
[users] [u]
ON
[p].[id_name] = [u].[id]
WHERE
[p].[date] >= #2017-01-01#
GROUP BY
[u].[id],
[u].[name]
ORDER BY
max([p].[date]) DESC
Now I need to transform it into Linq query. This my attempt but it's not working.
"Key" is not a member of type "System.Collections.Generic.IEnumerable'1[VB$AnonymousType_2'2[pob,users]]".
Using db = New DbContext() With {.InlineParameters = True}
Dim query1 = From p In db.pob
Join u In db.users On p.id_name Equals u.id
Where p.date >= New Date(2017, 1, 1)
Group New With {p, u} By pu = New With {Key u.id, Key u.name} Into pg = Group
Select New RecentUser With
{
.id = pu.id,
.name = pu.name,
.LastDateOfUse = pg.Max(Function(f) f.p.date)
}
query1 = query1.OrderByDescending(Function(f) f.LastDateOfUse).Take(5)
Return query1.ToList
End Using
If I remove .LastDateOfUse = pg.Max(Function(f) f.p.Date) like below it works. By 'works' I mean there is no exception but of course result of query is wrong however grouping is done properly.
Using db = New DbContext() With {.InlineParameters = True}
Dim query1 = From p In db.pob
Join u In db.users On p.id_name Equals u.id
Where p.date >= New Date(2017, 1, 1)
Group New With {p, u} By pu = New With {Key u.id, Key u.name} Into pg = Group
Select New RecentUser With
{
.id = pu.id,
.name = pu.name
}
Return query1.ToList
End Using
Edit
I also tried going through navigation properties like below, but again I receive the same error.
Using db = New DbContext() With {.InlineParameters = True}
Dim query1 = From p In db.pob
Where p.date >= New Date(2017, 1, 1)
Group p By pu = New With {Key u.User.id, Key u.User.name} Into pg = Group
Select New RecentUser With
{
.id = pu.id,
.name = pu.name
.LastDateOfUse = pg.Max(Function(f) f.date)
}
query1 = query1.OrderByDescending(Function(f) f.LastDateOfUse).Take(5)
Return query1.ToList
End Using
And again if I remove .LastDateOfUse = pg.Max(Function(f) f.p.Date) like below it starts to work (proper grouping, wrong overall result).
Using db = New DbContext() With {.InlineParameters = True}
Dim query1 = From p In db.pob
Where p.date >= New Date(2017, 1, 1)
Group p By pu = New With {Key u.User.id, Key u.User.name} Into pg = Group
Select New RecentUser With
{
.id = pu.id,
.name = pu.name
}
Return query1.ToList
End Using
How can I transform above Sql query to Linq? (preferable answer in VB.Net but C# is ok too)
Solution
There is no solution yet. It looks like VB has bad Linq queries resolver - it creates unexpected method chain that can not be converted to SQL.
So instead
Group By ... Into pg = Group
we need
Group By ... Into LastDateOfUse = p.Max(Function(f) f.date).
See below full query.
Using db = New DbContext() With {.InlineParameters = True}
Dim query1 = From p In db.pob
Where p.date >= New Date(2017, 1, 1)
Group p By pu = New With {Key u.User.id, Key u.User.name} Into LastDateOfUse = p.Max(Function(f) f.date)
Select New RecentUser With
{
.id = pu.id,
.name = pu.name
.LastDateOfUse = LastDateOfUse
}
Return query1.ToList
End Using
Another problem with lambda syntax
Using lambda syntax we receive another exception.
Dim query = db.pob.
Where(Function(f) f.date >= New Date(2017, 1, 1).
GroupBy(Function(f) New With
{
Key .userid= f.user.id,
Key .username = f.user.name
}).Select(Function(f) New RecentUser With
{
.id = f.Key.userid,
.name = f.Key.username,
.LastDateOfUse = f.Max(Function(g) g.date)
}).ToList
Exception
VB.NET compiler adds unnecessary Convert to IEnumerable when generating Expression Tree.
An unhandled exception of type LinqToDB.Linq.LinqException occurred in linq2db.dll
Convert(f).Select(g => g.Date).Max() cannot be converted to SQL
GitHub
I posted an issue here.
Svyatoslav Danyliv based on my issue opened his own here.

EPPlus Pivot Table - Copy Values to New Sheet

I've successfully created a pivot table using EPPlus. The pivot table resides in a seperate sheet from the raw data. I would like to copy the pivot table data to a new, third, sheet, but just the values, not the pivot defintions. Does EPPlus support this?
You can just copy the datasource range via Cache Definition:
public void PivotDataCopy()
{
const string FORMATCURRENCY = "#,###;[Red](#,###)";
var file = new FileInfo(#"c:\temp\temp.xlsx");
if (file.Exists)
file.Delete();
var pck = new ExcelPackage(file);
var workbook = pck.Workbook;
var dataworksheet = workbook.Worksheets.Add("datasheet");
//The data
dataworksheet.Cells["A20"].Value = "Col1";
dataworksheet.Cells["A21"].Value = "sdf";
dataworksheet.Cells["A22"].Value = "wer";
dataworksheet.Cells["A23"].Value = "ghgh";
dataworksheet.Cells["A24"].Value = "sdf";
dataworksheet.Cells["A25"].Value = "wer";
dataworksheet.Cells["B20"].Value = "Col2";
dataworksheet.Cells["B21"].Value = "Group A";
dataworksheet.Cells["B22"].Value = "Group B";
dataworksheet.Cells["B23"].Value = "Group A";
dataworksheet.Cells["B24"].Value = "Group C";
dataworksheet.Cells["B25"].Value = "Group A";
dataworksheet.Cells["C20"].Value = "Col3";
dataworksheet.Cells["C21"].Value = 453.5;
dataworksheet.Cells["C22"].Value = 634.5;
dataworksheet.Cells["C23"].Value = 274.5;
dataworksheet.Cells["C24"].Value = 453.5;
dataworksheet.Cells["C25"].Value = 634.5;
dataworksheet.Cells["D20"].Value = "Col4";
dataworksheet.Cells["D21"].Value = 686468;
dataworksheet.Cells["D22"].Value = 996440;
dataworksheet.Cells["D23"].Value = 185780;
dataworksheet.Cells["D24"].Value = 686468;
dataworksheet.Cells["D25"].Value = 996440;
//The pivot table
var pivotworksheet = workbook.Worksheets.Add("pivotsheet");
var pivotTable = pivotworksheet.PivotTables.Add(pivotworksheet.Cells["A1"], dataworksheet.Cells["A20:D29"], "test");
//The label row field
pivotTable.RowFields.Add(pivotTable.Fields["Col1"]);
pivotTable.DataOnRows = false;
//The data fields
var field = pivotTable.DataFields.Add(pivotTable.Fields["Col3"]);
field.Name = "Sum of Col2";
field.Function = DataFieldFunctions.Sum;
field.Format = FORMATCURRENCY;
field = pivotTable.DataFields.Add(pivotTable.Fields["Col4"]);
field.Name = "Sum of Col3";
field.Function = DataFieldFunctions.Sum;
field.Format = FORMATCURRENCY;
//Get the pivot table data source
var newworksheet = workbook.Worksheets.Add("newworksheet");
var pivotdatasourcerange = pivotTable.CacheDefinition.SourceRange;
pivotdatasourcerange.Copy(newworksheet.Cells["A1"]);
pck.Save();
}
EDIT: Doing with a VBA macro which then resaves the sheet as a non-macro XLSX:
public void PivotDataCopy()
{
const string FORMATCURRENCY = "#,###;[Red](#,###)";
var file = new FileInfo(#"c:\temp\temp.xlsm");
if (file.Exists)
file.Delete();
var pck = new ExcelPackage(file);
var workbook = pck.Workbook;
var dataworksheet = workbook.Worksheets.Add("datasheet");
//The data
dataworksheet.Cells["A20"].Value = "Col1";
dataworksheet.Cells["A21"].Value = "sdf";
dataworksheet.Cells["A22"].Value = "wer";
dataworksheet.Cells["A23"].Value = "ghgh";
dataworksheet.Cells["A24"].Value = "sdf";
dataworksheet.Cells["A25"].Value = "wer";
dataworksheet.Cells["B20"].Value = "Col2";
dataworksheet.Cells["B21"].Value = "Group A";
dataworksheet.Cells["B22"].Value = "Group B";
dataworksheet.Cells["B23"].Value = "Group A";
dataworksheet.Cells["B24"].Value = "Group C";
dataworksheet.Cells["B25"].Value = "Group A";
dataworksheet.Cells["C20"].Value = "Col3";
dataworksheet.Cells["C21"].Value = 453.5;
dataworksheet.Cells["C22"].Value = 634.5;
dataworksheet.Cells["C23"].Value = 274.5;
dataworksheet.Cells["C24"].Value = 453.5;
dataworksheet.Cells["C25"].Value = 634.5;
dataworksheet.Cells["D20"].Value = "Col4";
dataworksheet.Cells["D21"].Value = 686468;
dataworksheet.Cells["D22"].Value = 996440;
dataworksheet.Cells["D23"].Value = 185780;
dataworksheet.Cells["D24"].Value = 686468;
dataworksheet.Cells["D25"].Value = 996440;
//The pivot table
var pivotworksheet = workbook.Worksheets.Add("pivotsheet");
var pivotTable = pivotworksheet.PivotTables.Add(pivotworksheet.Cells["A1"], dataworksheet.Cells["A20:D29"], "test");
//The label row field
pivotTable.RowFields.Add(pivotTable.Fields["Col1"]);
pivotTable.DataOnRows = false;
//The data fields
var field = pivotTable.DataFields.Add(pivotTable.Fields["Col3"]);
field.Name = "Sum of Col2";
field.Function = DataFieldFunctions.Sum;
field.Format = FORMATCURRENCY;
field = pivotTable.DataFields.Add(pivotTable.Fields["Col4"]);
field.Name = "Sum of Col3";
field.Function = DataFieldFunctions.Sum;
field.Format = FORMATCURRENCY;
//add the macro to copy the table data on open
workbook.Worksheets.Add("newworksheet");
var sb = new StringBuilder();
sb.AppendLine("Private Sub Workbook_SheetCalculate(ByVal Sh As Object)");
sb.AppendLine(" Sheets(\"pivotsheet\").Cells.Copy");
sb.AppendLine(" Sheets(\"newworksheet\").Range(\"A1\").PasteSpecial Paste:=xlPasteValues");
sb.AppendLine(" Selection.Clear");
sb.AppendLine(" Application.DisplayAlerts = False");
sb.AppendLine(String.Format(" ActiveWorkbook.SaveAs \"{0}\", xlOpenXMLWorkbook", file.FullName.Replace("xlsm", "xlsx")));
sb.AppendLine(" Application.DisplayAlerts = True");
sb.AppendLine("End Sub");
pck.Workbook.CreateVBAProject();
pck.Workbook.CodeModule.Code = sb.ToString();
pck.Save();
}

Covert Linq to Expression Tree

Need help in converting this linq query to Expression Tree
Dim query = (From _row In table.Rows
Group _row By vGroup = _row("VENDOR")
Into VendorGroup = Group
Select New With {
Key vGroup,
.PI = VendorGroup.Sum(Function(r) r("PI")),
.ST = VendorGroup.Sum(Function(r) r("ST")),
.IS = VendorGroup.Sum(Function(r) r("IS")),
.RR = VendorGroup.Sum(Function(r) r("RR"))
}).ToList
You can try converting to IQueryable then pulling out the Expression property:
Dim expression = (From _row In table.Rows
Group _row By vGroup = _row("VENDOR")
Into VendorGroup = Group
Select New With {
Key vGroup,
.PI = VendorGroup.Sum(Function(r) r("PI")),
.ST = VendorGroup.Sum(Function(r) r("ST")),
.IS = VendorGroup.Sum(Function(r) r("IS")),
.RR = VendorGroup.Sum(Function(r) r("RR"))
}).AsQueryable()
.Expression
but the expression you get back may vary depending on the query provider you're using.