Entity Framework - convert LINQ method chain with SelectMany to query syntax - c#

I'd like to ask a following question.
I'm building a query which will return some details about stored email packages.
Relationships:
Packages 1-------N Addresses 1------N OutboundPackages
I would like to convert testOK query to expression syntax, specifically the following statement:
referenceGuids = pkg.PackageAddresses.SelectMany(s=>s.AddressOutboundPackages).Select(s=>s.Reference)
Complete example:
var test = (from stamp in IssuedStamps
join pkg in Packages.Include(i=>i.PackageAddresses) on stamp.Id equals pkg.IssuedStampId
join addr in Addresses on pkg.Id equals addr.Package_Id
join outb in OutboundPackages on addr.Id equals outb.Address_Id
where stamp.PortalUserId == "f31c2582-f663-4f2e-a9f7-d41ba138f86c" && stamp.Used
//I'd like to convert the following SelectMany LINQ method chain expression to query syntax
//let referenceGuids = pkg.PackageAddresses.SelectMany(s=>s.AddressOutboundPackages).Select(s=>s.Reference)
select new
{
StampId = stamp.Id,
RecipientEmail = pkg.PackageAddresses.FirstOrDefault(x => x.AddressType == 1).EmailAddress,
SenderEmail = pkg.PackageAddresses.FirstOrDefault(x => x.AddressType == 0).EmailAddress,
DateSent = pkg.ReceivedDate,
Remarks = stamp.Description,
Ref = referenceGuids,
Subject = pkg.Subject,
IsMassMailing = pkg.ProcessingPackageId == null || pkg.ProcessingPackageId == string.Empty
}
).ToList();
var testOK = (from stamp in IssuedStamps
join pkg in Packages.Include(i=>i.PackageAddresses.Select(s=>s.AddressOutboundPackages)).Include(i=>i.PackageAddresses) on stamp.Id equals pkg.IssuedStampId
where stamp.PortalUserId == "f31c2582-f663-4f2e-a9f7-d41ba138f86c" && stamp.Used
let referenceGuids = pkg.PackageAddresses.SelectMany(s=>s.AddressOutboundPackages).Select(s=>s.Reference)
select new
{
StampId = stamp.Id,
RecipientEmail = pkg.PackageAddresses.FirstOrDefault(x => x.AddressType == 1).EmailAddress,
SenderEmail = pkg.PackageAddresses.FirstOrDefault(x => x.AddressType == 0).EmailAddress,
DateSent = pkg.ReceivedDate,
Remarks = stamp.Description,
Ref = pkg.PackageAddresses.SelectMany(s => s.AddressOutboundPackages).Select(s => s.Reference),
Subject = pkg.Subject,
IsMassMailing = pkg.ProcessingPackageId == null || pkg.ProcessingPackageId == string.Empty
}
).ToList();

That's easy.
referenceGuids = pkg.PackageAddresses
.SelectMany(s => s.AddressOutboundPackages)
.Select(s => s.Reference)
goes to
referenceGuids = (from pa in pkg.PackageAddresses
from aop in pa.AddressOutboundPackages
select aop.Reference)

Related

LinqToDb: Rank is server-side method

I am trying to use linq2db.EntityFrameworkCore for some of its windowing functions, such as RANK().
Below is my implementation:
var abc = (from tl in _repo.Context.TransferLink
join tlt in _repo.Context.TransferLinkType on new { TLinkId = tl.TransferLinkTypeId, EType = "Deviance" } equals new { TLinkId = tlt.TransferLinkTypeId, EType = tlt.EnumTransferLinkType }
//let duplicateCount = _repo.Context.TransferLink.Where(tl1 => tl1.SecondaryTransferId != null && tl.SecondaryTransferId != null &&
//tl1.SecondaryTransferId == tl.SecondaryTransferId.Value).Count()
where
(allTransferIds.Contains(tl.PrimaryTransferId) || allTransferIds.Contains(tl.SecondaryTransferId)) &&
!tl.Archived
select new
{
TransferLinkId = tl.TransferLinkId,
TransferLinktypeId = tl.TransferLinkTypeId,
PrimaryTransferId = tl.PrimaryTransferId,
SecondaryTransferId = tl.SecondaryTransferId,
DuplicateCount = Sql.Ext.Count(tl.TransferLinkId)
.Over()
.PartitionBy(tl.SecondaryTransferId)
.ToValue()
UpdatedDate = tl.UpdatedDate,
RankVal = Sql.Ext.Rank()
.Over()
.PartitionBy(tl.TransferLinkTypeId, tl.SecondaryTransferId)
.OrderByDesc(tl.UpdatedDate)
.ThenBy(tl.TransferLinkId)
.ToValue()
}).ToList();
This code throws the exception:
Rank is server-side method
I have tried searching for a solution, but could not find any.
Any idea?
For using linq2db.EntityFrameworkCore you have to switch to library's LINQ provider. It can be done by simple ToLinqToDB() call.
var query = /* some EF Core query */
query = query.ToLinqToDB();
var result = query.ToList();

SQL to Linq statement

I've got this SQL statement that I'm trying to convert to linq:
SELECT i.*
FROM Issues i
WHERE IssueID IN (SELECT ChildIssueId
FROM LinkedIssues
WHERE IssueId = 28438)
OR IssueID IN (SELECT IssueId
FROM LinkedIssues
WHERE ChildIssueId = 28438)
Here's what the data in the table looks like:
So in the sql above, I get issues 19220, 28436, & 28440 back. Here's what I've tried with no luck:
var childIssues = (from i in Issues
join li in LinkedIssues
on i.IssueID equals li.IssueId
where (from li2 in LinkedIssues
where li.IssueId == 28438 || li.ChildIssueId == 28438
select li2).Contains(28438)
select new LinkedIssuesModel()
{
IssueID = li.ChildIssueId,
CustomerName = i.Room.Location.Customer.CustomerName,
LocationName = i.Room.Location.LocationName,
ReceivedDate = i.ReceivedDate,
IssueSummary = i.IssueSummary,
IssueDescription = i.IssueDescription
}).ToList();
I need to know how to convert SQL IN statements to linq. I have LinqPad but it doesn't convert it when I click the lambda button. I've also downloaded and tried Linqer but it throws an "Object not set to an instance Object" error.
Please try the following:
var childIssues = (from i in Issues
from li in LinkedIssues
where (li.IssueId == 28438 && li.ChildIssueId == i.IssueID)
|| (li.ChildIssueId == 28438 && li.IssueId == i.IssueID)
select new LinkedIssuesModel()
{
IssueID = li.ChildIssueId,
CustomerName = i.Room.Location.Customer.CustomerName,
LocationName = i.Room.Location.LocationName,
ReceivedDate = i.ReceivedDate,
IssueSummary = i.IssueSummary,
IssueDescription = i.IssueDescription
}).ToList();
EDIT: Fixed query to address li.ChildIssueId on the select.
You are not joining.
var childIssues = Issues.
Where(x => LinkedIssues.
Where(z => z.IssueId = 28438).
Select(z => z.ChildIssueId).
Contains(x.IssueID)
||
LinkedIssues.
Where(z => z.ChildIssueId = 28438).
Select(z => z.IssueId).
Contains(x.IssueID)
);

Linq Select Data based on a value in another table

I have the linq statements listed below and I want to restrict the records from one table based on the value in another table. This is the code I have which works:
using (context = new DocEntityConnection())
{
var Docs = context.tbDocsDetails.Where(md => md.IsCurrentDetails && md.tbDoc.StatusID == 9).ToList();
this.approves = context.tbDocApproves.ToList().Where(a => Docs.Select(x => x.DocID).ToList().Contains(a.DocID)).ToList();
return Docs.Select(md => GetDataItem(md)).ToList();
}
There is another table called tbDocStatus which has a DocId field too
I would like to only return records from tbDocDetails where tbDocdetails.DocId = tbDocStatus.DocId and tbDocStatus.StatusId = 4.
How would I add that to my code shown above?
That you need is a join
var Docs = from docDetail in context.tbDocsDetails
join docStatus in context.tbDocStatus
on docDetail.DocId = docStatus.DocId
where docStatus.StatusId == 4
select docDetail;
using (context = new DocEntityConnection())
{
var Docs = context.tbDocsDetails.Where(md => md.IsCurrentDetails && md.tbDoc.StatusID == 9).ToList();
var DocsFiltered = from d in Docs
join docStatus in context.tbDocStatus
on d.DocId equals docStatus.DocId
where docStatus.StatusId = 4
select d
this.approves = context.tbDocApproves.ToList().Where(a => Docs.Select(x => x.DocID).ToList().Contains(a.DocID)).ToList();
return DocsFiltered.Select(md => GetDataItem(md)).ToList();
}

Linq query syntax with PredicateBuilder?

Is it possible to use PredicateBuilder with LINQ query syntax? For example, building a basic search method, with many optional parameters. How can I add a where clause based on the predicate I have built?
public List<Entities.ProjectSearchResult> GetProjects(string projectName,
string projectLaunchName,
int? projectID, int? categoryID,
int? subCategoryID)
{
var predicate = PredicateBuilder.True<Entities.Project>();
if (!String.IsNullOrWhiteSpace(projectName))
predicate = predicate.And(p => p.ProjectName.Contains(projectName));
if (!String.IsNullOrWhiteSpace(projectLaunchName))
predicate = predicate.And(p => p.ProjectName.Contains(projectLaunchName));
if (projectID.HasValue)
predicate = predicate.And(p => p.ProjectId == projectID.Value);
if (categoryID.HasValue)
predicate = predicate.And(p => p.SectorCode == categoryID.Value);
if (subCategoryID.HasValue)
predicate = predicate.And(p => p.SubSectorCode == subCategoryID.Value);
using (CHIPSDbContext db = new CHIPSDbContext())
{
var query = (from p in db.Projects
join s in db.ProjectStatus on p.ProjectStatusCode equals s.ProjectStatusCode
join b in db.ProjectBrands on p.ProjectId equals b.ProjectId into brandList
from sublist in brandList.DefaultIfEmpty()
select new Entities.ProjectSearchResult
{
ProjectID = p.ProjectId,
ProjectName = p.ProjectName,
ProjectLaunchName = p.ProjectLaunchName,
Status = s.ProjectStatusDesc,
}).AsExpandable().ToList();
return query;
}
}
Build the predicate on the type you return instead, so that it's more clear from the calling method what you filter on.
var predicate = PredicateBuilder.True<Entities.ProjectSearchResult>(); // Expression with your type
if (!String.IsNullOrWhiteSpace(projectName))
predicate = predicate.And(p => p.ProjectName.Contains(projectName));
...
using (CHIPSDbContext db = new CHIPSDbContext())
{
var query = (from p in db.Projects
join s in db.ProjectStatus on p.ProjectStatusCode equals s.ProjectStatusCode
join b in db.ProjectBrands on p.ProjectId equals b.ProjectId into brandList
from sublist in brandList.DefaultIfEmpty()
select new Entities.ProjectSearchResult
{
ProjectID = p.ProjectId,
ProjectName = p.ProjectName,
ProjectLaunchName = p.ProjectLaunchName,
Status = s.ProjectStatusDesc,
})
.Where(predicate.Expand()) // Don't forget to expand predicate
.AsExpandable()
.ToList();
return query;
}

LINQ to Entities does not recognize the method 'System.Data.Entity.DbSet`1

var query = from cl in
(
from cl in _dataContext.Set<CLIENT>()
from cr in
_dataContext.Set<CLIENT_REL>()
.Where(m => m.CLIENT_CHILD_ID == cl.CLIENT_ID)
.DefaultIfEmpty()
.AsEnumerable()
select new {cl.CLIENT_ID, cl.CLIENT_NAME, cr.CLIENT_PARENT_ID, cl.CLIENT_CODE, cl.CLIENT_DESCR}
)
from pcl in
_dataContext.Set<CLIENT>().Where(p => p.CLIENT_ID == cl.CLIENT_PARENT_ID).DefaultIfEmpty()
select new ClientDetail
{
ClientId = cl.CLIENT_ID,
ClientName = cl.CLIENT_NAME,
ClientCode = cl.CLIENT_CODE,
ClientDescription = cl.CLIENT_DESCR,
ParentName = pcl.CLIENT_NAME
};
is throwing the following System.NotSupportedException
LINQ to Entities does not recognize the method 'System.Data.Entity.DbSet`1[Ika.Security.Data.Model.CLIENT_REL] SetCLIENT_REL' method, and this method cannot be translated into a store expression.
What am I doing wrong ?

Categories

Resources