Using AND in JOIN in LINQ - c#

I have such a SQL:
SELECT Items.ItemCode AS code, Items.ItemName AS name, ISNULL(PLID.PriceOverule,Items.ItemPrice) AS price from tblPLItemsDetail PLID
INNER JOIN tblItems Items ON PLID.ItemID = Items.ItemID
AND Items.ValidityTo IS NULL
WHERE PLItemID = #PLItemID
AND PLID.ValidityTo IS NULL
AND (PLID.ValidityFrom >= #LastUpdated OR #LastUpdated IS NULL)
I put this on LINQ:
details = context.TblPlitemsDetail
.Join(imisContext.TblItems,
p => p.ItemId,
i => i.ItemId,
(p, i) => new { TblPlitemsDetail = p, TblItems = i })
.Where(r => r.TblPlitemsDetail.PlitemId == PLItemID
&& r.TblPlitemsDetail.ValidityTo == null
&& (r.TblPlitemsDetail.ValidityFrom >= Convert.ToDateTime(model.last_update_date) || model.last_update_date == null))
.Select(x => new CodeNamePrice()
{
code = x.TblItems.ItemCode,
name = x.TblItems.ItemName,
price = (x.TblPlitemsDetail.PriceOverule == null) ? x.TblItems.ItemPrice.ToString() : x.TblPlitemsDetail.PriceOverule.ToString()
}).ToList();
I've rewritten most of the code but I have not implemented the AND Items.ValidityTo IS NULL predicate in the JOIN.
How to do it correctly?

As it is an INNER JOIN you can specify the extra predicate (Items.ValidityTo IS NULL) in a LINQ Where clause:
details = context.TblPlitemsDetail
.Join(imisContext.TblItems, p => p.ItemId, i => i.ItemId, (p, i) => new { TblPlitemsDetail = p, TblItems = i })
.Where(r => !r.TblItems.ValidityTo.HasValue)
.Where(r => r.TblPlitemsDetail.PlitemId == PLItemID && r.TblPlitemsDetail.ValidityTo == null && (r.TblPlitemsDetail.ValidityFrom >= Convert.ToDateTime(model.last_update_date) || model.last_update_date == null))
.Select(x => new CodeNamePrice() { code = x.TblItems.ItemCode, name = x.TblItems.ItemName, price = (x.TblPlitemsDetail.PriceOverule == null) ? x.TblItems.ItemPrice.ToString() : x.TblPlitemsDetail.PriceOverule.ToString() }).ToList();

Related

DefaultIfEmpty() does not handle empty collections

I've been trying to left join the table and they are in a one-to-many relationship.
I have written a SQL query and trying to convert it into LINQ for my ASP.NET Core application.
My sql query is as follows:
SELECT ap.SystemId,
ap.AccessRequiredToId,
cb.AccessAreaManagementId,
ap.EquipmentTagId,
COUNT(ap.Name) [Count]
FROM ApplicationForms ap LEFT JOIN AccessAreaCheckBoxes cb
ON n ap.RecordId = cb.RecordId
WHERE EndDate IS NULL AND (Checked IS NULL OR Checked = 1)
GROUP BY ap.SystemId, ap.AccessRequiredToId, cb.AccessAreaManagementId, ap.EquipmentTagId
SQL Result
And my LINQ is as follows:
var active = _context.ApplicationForms
.Where(w => w.EndDate == null)
.GroupJoin(_context.AccessAreaCheckBoxes
.Where(w => (w.AccessAreaManagement == null || w.Checked == true)),
x => x.RecordId,
y => y.RecordId,
(x, y) => new { ApplicationForms = x, AccessAreaCheckBoxes = y })
.SelectMany(x => x.AccessAreaCheckBoxes.DefaultIfEmpty(),
(x, y) => new { x.ApplicationForms, AccessAreaCheckBoxes = y })
.GroupBy(g => new { g.ApplicationForms.System, g.ApplicationForms.AccessRequiredTo, g.AccessAreaCheckBoxes.AccessAreaManagement, g.ApplicationForms.EquipmentTag })
.Select(s => new RecordViewModel
{
System = s.Key.System.Name,
AccessRequiredTo = s.Key.AccessRequiredTo.Name,
AccessArea = s.Key.AccessAreaManagement.Name,
EquipmentTag = s.Key.EquipmentTag.Name,
Count = s.Count()
}).ToList();
Everything is working well except it doesn't show the rows with the NULL value.
Did I miss out something in my LINQ?
Any help would be greatly appreciated!
This is what I do in the end, post here for your reference.
var active = (from ap in _context.ApplicationForms
join cb in _context.AccessAreaCheckBoxes
on ap.RecordId equals cb.RecordId into j1
from j2 in j1.DefaultIfEmpty()
where ap.EndDate == null
&& (j2.AccessAreaManagement == null || j2.Checked == true)
group new { ap.System, ap.AccessRequiredTo, j2.AccessAreaManagement, ap.EquipmentTag }
by new { System = ap.System.Name, Building = ap.AccessRequiredTo.Name, AccessArea = j2.AccessAreaManagement.Name, Equipment = ap.EquipmentTag.Name } into grp
select new RecordViewModel
{
System = grp.Key.System,
AccessRequiredTo = grp.Key.Building,
AccessArea = grp.Key.AccessArea,
EquipmentTag = grp.Key.Equipment,
Count = grp.Count()
}).ToList();

c# Lambda referencing class object in Select method

I've written this code which works:
var uniqueCustomerIdList = services
.GroupBy(x => x.CustomerId)
.Select(cl => new Customer
{
CustomerId = cl.First().CustomerId,
CustomerName = cl.First().CompanyName,
PdfServices = services.Where(x => x.CustomerId == cl.First().CustomerId).ToList(),
PdfServiceLines = services.Where(x => x.CustomerId == cl.First().CustomerId).ToList()
.GroupBy(l => l.ServiceDescription)
.Select(cy => new PdfServiceLine
{
ServiceName = cy.First().ServiceDescription,
Quantity = cy.Count(),
UnitPrice = cy.First().PlanCharge,
ServiceCharges = services.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill),
UsageCharges = usage.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.Charge),
Total = cy.Sum(c => c.PlanCharge),
}).ToList(),
PdfUsages = usage.Where(x => x.CustomerId == cl.First().CustomerId).ToList()
})
.ToList();
I wanted to know if it's possible to reference values from the outer Select statement in the inner statement? As it looks rather clunky at the moment.
For instance in the outer Customer select I use PdfServices - can I use that in the inner select where I have ServiceCharges?
ServiceCharges = PdfServices.Where(s => s.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill)
instead of
ServiceCharges = services.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill),
Thanks,
Lee.
The results that you want to re-use are members of an anonymous object, not variables. As such, you cannot expect them to be available, like a variable would be, to the inner lambda. If you re-wrote your statement, you could store them in intermediate variables:
var uniqueCustomerIdList = services
.GroupBy(x => x.CustomerId)
.Select(cl =>
{
var pdfServices = services.Where(x => x.CustomerId == cl.First().CustomerId).ToList();
return new Customer
{
CustomerId = cl.First().CustomerId,
CustomerName = cl.First().CompanyName,
PdfServices = pdfServices,
PdfServiceLines = pdfServices
.GroupBy(l => l.ServiceDescription)
.Select(cy => new PdfServiceLine
{
ServiceName = cy.First().ServiceDescription,
Quantity = cy.Count(),
UnitPrice = cy.First().PlanCharge,
ServiceCharges = services.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill),
UsageCharges = usage.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.Charge),
Total = cy.Sum(c => c.PlanCharge),
}).ToList(),
PdfUsages = usage.Where(x => x.CustomerId == cl.First().CustomerId).ToList()
};
})
.ToList();
Note that the lamda body now uses curly braces and a return statement. This is not convertible to an expression tree, and some ORM frameworks, like Entity Framework, will not be able to translate the lamda into SQL.

Entity Framework querying error

Why does this work:
List<Item> items = ndb.Items.Where(m => m.ProductId == id).OrderByDescending(m => m.Id).ToList();
int itemid = items[0].Id;
bool wlexists = ndb.Wishlists.Any(m => m.ItemId == itemid && m.UserEmail == User.Identity.Name);
And this doesn't :
List<Item> items = ndb.Items.Where(m => m.ProductId == id).OrderByDescending(m => m.Id).ToList();
bool wlexists = ndb.Wishlists.Any(m => m.ItemId == items[0].Id && m.UserEmail == User.Identity.Name);
It must work if the items had value i.e not null . What error you are getting???
Do like this.
List<Item> items = ndb.Items.Where(m => m.ProductId == id).OrderByDescending(m => m.Id).ToList();
if(items!=null)
bool wlexists = ndb.Wishlists.Any(m => m.ItemId == items[0].Id && m.UserEmail == User.Identity.Name);

Convert Sql to LINQ complex C# function to readable sql server string

I read a lot about getting a readable sql server query string from a c# linq to sql function, but could not figure out how to actually do so, maybe because the project i am working on is really complicated.
I'm pasting a pice of a code that i want to convert to sql (select * from bonds join etc.)
public List<EntBondPortfolio> GetBondsForPortfolio(List<int> groups, List<int> ratings,
List<int> collaterals, List<int> companies, List<int> countries, List<int> fields,
List<int> currencies, DateTime? fromExpirationDate, DateTime? untilExpirationDate, bool? perpetual, int? sortOrder = 1)
{
// Get Bonds
return (from bond in DALLinqClasses.Instance.BONDs
join company in DALLinqClasses.Instance.COMPANies on bond.Company_ID equals company.CompanyID
into companyJoin
from companyJ in companyJoin.DefaultIfEmpty()
join sellBuy in DALLinqClasses.Instance.SELL_BUY_OPERATIONs on bond.BondID equals sellBuy.Investment_ID
join account in DALLinqClasses.Instance.BANK_ACCOUNTs on sellBuy.BankAccount_ID equals account.BankAccountID
join groupsTable in DALLinqClasses.Instance.GROUPs on account.GroupAccount_ID equals groupsTable.GroupID
join customer in DALLinqClasses.Instance.CUSTOMERs on groupsTable.Customer_ID equals customer.CustomerID
join rating in DALLinqClasses.Instance.RATINGs on bond.Rating_ID equals rating.RatingID
into ratingJoin
from ratingJ in ratingJoin.DefaultIfEmpty()
join currency in DALLinqClasses.Instance.CURRENCies on bond.Currency_ID equals currency.CurrencyID
join country in DALLinqClasses.Instance.COUNTRies on bond.Country_ID equals country.CountryID
into countryJoin
from countryJ in countryJoin.DefaultIfEmpty()
join field in DALLinqClasses.Instance.FIELDs on bond.Field_ID equals field.FieldID
into fieldJoin
from fieldJ in fieldJoin.DefaultIfEmpty()
join collateral in DALLinqClasses.Instance.RISC_LEVELs on bond.RiscLevel_ID equals collateral.RiscLevelID
into collateralJoin
from collateralJ in collateralJoin.DefaultIfEmpty()
join orderi in // For order by
DALLinqClasses.Instance.PORTFOLIO_ORDERs.Where(x => x.InvestmentType_ID == (int)INVESTMENT_TYPES.BONDS)
on new EntTwoInts { BankAccountID = bond.BondID, GroupID = groupsTable.GroupID }
equals
new EntTwoInts { BankAccountID = orderi.Investment_ID, GroupID = orderi.Group_ID }
into orderJoin
from orderJ in orderJoin.DefaultIfEmpty()
where sellBuy.InvestmentType_ID == (int)INVESTMENT_TYPES.BONDS
&& groups.Contains(groupsTable.GroupID)
&& (collaterals.Contains(bond.RiscLevel_ID ?? -1) || collaterals.Contains(-1))
&& (ratings.Contains(bond.Rating_ID ?? -1) || ratings.Contains(-1))
&& (companies.Contains(bond.Company_ID ?? -1) || companies.Contains(-1))
&& (countries.Contains(bond.Country_ID ?? -1) || countries.Contains(-1))
&& (fields.Contains(bond.Field_ID ?? -1) || fields.Contains(-1))
&& (currencies.Contains(bond.Currency_ID) || currencies.Contains(-1))
&& (bond.ExpirationDate >= fromExpirationDate || fromExpirationDate == null)
&& (bond.ExpirationDate <= untilExpirationDate || untilExpirationDate == null)
&& (perpetual == bond.Perpetual || perpetual == null)
group sellBuy by new { bond, companyJ, groupsTable, account, orderJ, customer, ratingJ, collateralJ, countryJ, fieldJ } into g
orderby g.Key.orderJ != null ? false : true, g.Key.orderJ.SortOrder, g.Key.groupsTable.GroupName, g.Key.companyJ.CompanyName
select new EntBondPortfolio
{
Rating = g.Key.ratingJ.RatingName,
RiscLevel = g.Key.collateralJ.RiscLevelName,
Group = g.Key.groupsTable.GroupName,
Client = g.Key.customer.FirstName + ' ' + g.Key.customer.LastName,
GroupId = g.Key.groupsTable.GroupID,
Company = g.Key.companyJ.CompanyName,
CurrencyId = g.Key.bond.Currency_ID,
BondId = g.Key.bond.BondID,
CallText = g.Key.bond.CallText,
Field = g.Key.fieldJ.FieldName,
Country = g.Key.countryJ.CountryName,
CouponPercent = g.Key.bond.CouponPercent,
// Get total sum of coupons in checking account of current bond
CouponsPaid = DALLinqClasses.Instance.CHECKING_ACCOUNTs.
Where(x => x.ActionType_ID == (int)ACTION_TYPES.COUPON
&& g.Select(y => y.SellBuyOperationID).
Contains(x.SellBuyOperation_ID.GetValueOrDefault()))
.Sum(s => s.ActualSum),
ExpirationDate = g.Key.bond.ExpirationDate,
FaceValue = (g.Where(x => x.IsSell == false).Sum(x => x.FaceValue) - (g.Where(x => x.IsSell == true).Sum(x => x.FaceValue) ?? 0)),
Isin = g.Key.bond.Isin,
LastBuyDate = g.Where(x => x.IsSell == false).Max(x => x.SellBuyOperationDate),
CurrentPrice = DALInvestmentTypes.Instance.GetCurrentPriceOfBond(g.Key.bond.BondID, BONDS_HISTORY_TYPES.MarketValue),
CurrentYield = DALInvestmentTypes.Instance.GetCurrentPriceOfBond(g.Key.bond.BondID, BONDS_HISTORY_TYPES.Yield),
CurrentAcrInterest = DALInvestmentTypes.Instance.GetCurrentPriceOfBond(g.Key.bond.BondID, BONDS_HISTORY_TYPES.AcrInterest),
PurchasePrice = g.Where(x => x.IsSell == false).Sum(x => x.FaceValue) == 0 ? 0 :
g.Where(x => x.IsSell == false).Sum(x => x.FaceValue * x.Price)
/ g.Where(x => x.IsSell == false).Sum(x => x.FaceValue),
Instruction = DALInstructions.Instance.IsInvestmentHaveInstruction(INVESTMENT_TYPES.BONDS, g.Key.bond.BondID, g.Key.account.BankAccountID),
}).ToList();
}

Multiple Select and Join with LINQ and Lambda

How can I do this query using LINQ and LAMBDA ?
QUERY
Select san_negocio.imovel_id
,san_negocio.negocio_id
,san_imovel.credenciada_id
,san_proposta.proposta_id
,san_proposta.credenciada_id
from san_negocio
join san_proposta
on san_negocio.imovel_id = san_proposta.imovel_id
join san_imovel
on san_negocio.imovel_id = san_imovel.imovel_id
where san_negocio.credenciadacaptadora_id is null
and san_negocio.credenciadavendedora_id is null
and san_proposta.statusproposta_id = 2
I've tried:
var objetos = db.San_Negocio.Join(db.San_Proposta, a => a.Imovel_Id, b => b.Imovel_Id, (a, b) => new { San_Negocio = a, San_Proposta = b })
.Join(db.San_Imovel, a => a.San_Negocio.Imovel_Id, c => c.Imovel_Id, (a, c) => new { San_Negocio = a, San_Imovel = c })
.Where(a => a.San_Negocio.San_Negocio.CredenciadaCaptadora_Id == null && a.San_Negocio.San_Negocio.CredenciadaVendedora_Id == null)
.Select(a => new { a.San_Negocio.San_Negocio.Negocio_Id,
a.San_Negocio.San_Negocio.Imovel_Id,
a.San_Imovel.Credenciada_Id });
My doubt is in my Select. How can I call my San_Proposta table ?
You are hiding San_Proposta within a field called San_Negocio, so calling a.San_Negocio.San_Proposta will access it, but I recommend writing your joins in a way that fields aren't nested, like this:
var objetos = db.San_Negocio
.Join(db.San_Proposta,
a => a.Imovel_Id,
b => b.Imovel_Id,
(a, b) => new { San_Negocio = a, San_Proposta = b })
.Join(db.San_Imovel,
a => a.San_Negocio.Imovel_Id,
c => c.Imovel_Id,
(a, c) => new { a.San_Negocio, a.San_Proposta, San_Imovel = c })
.Where(a => a.San_Negocio.CredenciadaCaptadora_Id == null &&
a.San_Negocio.CredenciadaVendedora_Id == null)
.Select(a => new
{
a.San_Negocio.Negocio_Id,
a.San_Negocio.Imovel_Id,
a.San_Proposta.San_Proposta_Id,
a.San_Imovel.Credenciada_Id
});
Here is a proper linq statement:
from neg in db.san_negocio
join prop in san_proposta
on neg.imovel.id equals prop.imovel_id
join imo in san_imovel
on neg.imovel_id = imo.imovel_id
where neg.credenciadacaptadora_id == null &&
neg.credenciadavendedora_id == null &&
prop.statusproposta_id == 2
select new {
ImovelID = neg.imovel_id,
NegocioID = neg.negocio_id,
Imo_CredenciadaID = imo.credenciada_id,
PropostaID = prop.proposta_id
Prop_CredenciadaID = prop.credenciada_id
};
This will create an IQueryable of anonymous objects with the listed properties above.

Categories

Resources