Dynamic LINQ Multiple Where Clause - c#

Still really struggling with this and appear to be going round in circles.
I have the following code that is driving me nuts. It should populate a list of items to be used in an autocomplete text box:
public string[] GetAutoComplete(string prefixText, int count)
{
string memberid = HttpContext.Current.Session["MemberID"].ToString();
string locationid = HttpContext.Current.Session["LocationID"].ToString();
string inhouse = HttpContext.Current.Session["Inhouse"].ToString();
string supplier = HttpContext.Current.Session["Supplier"].ToString();
string groupw = HttpContext.Current.Session["Group"].ToString();
string external = HttpContext.Current.Session["External"].ToString();
MyEnts autocomplete = new MyEnts();
var r = from p in autocomplete.tblAutoCompletes
where p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText)
select p.ACItem;
if (inhouse == "Inhouse")
r = r.Where(p => p == inhouse);
if (supplier == "Supplier")
r = r.Where(p => p == supplier);
if (groupw == "Group")
r = r.Where(p => p == groupw);
if (external == "External")
r = r.Where(p => p == external);
r.OrderBy(p => p);
return r.ToArray();
What I am trying to retrieve with the dynamic where clause along the lines of the following.
Should inhouse = "Inhouse", then the list of items should include the word "Inhouse". If inhouse != "Inhouse", the word "Inhouse" should be excluded from the list.
This same logic should then be applied across the different where clauses i.e. Supplier, Group, External.
I genuinely have tried lots of different methods but I cannot for the life of me get the thing to work and it's frustrating me somewhat.
If anyone can suggest a way of doing this, you will either get a big kiss or a big frosty beer should our paths ever cross.

Not exactly sure about your problem here but if you want to exclude then shouldn't the code be something like
if (inhouse == "Inhouse")
r = r.Where(p => p == inhouse);
else
r = r.Where(p => p != inhouse);
Oh! if you want just exclusion then the code should be something like
if (inhouse != "Inhouse")
r = r.Where(p => p != inhouse);

If the set of values to include/exclude is known at compile-time (as appears to be the case in your example), I think this can be managed with one query:
string memberid = HttpContext.Current.Session["MemberID"].ToString();
string inhouse = HttpContext.Current.Session["Inhouse"].ToString();
string supplier = HttpContext.Current.Session["Supplier"].ToString();
bool includeInHouse = (inhouse == "Inhouse");
bool includeSupplier = (supplier == "Supplier");
MyEnts autocomplete = new MyEnts();
var r = from p in autocomplete.tblAutoCompletes
where (p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText))
&& (includeInHouse || (p.ACItem != "InHouse"))
&& (includeSupplier || (p.ACItem != "Supplier"))
select p.ACItem;
r.OrderBy(p => p.ACItem);
return r.ToArray();
I've eliminated a couple cases for brevity.

Wouldn't each of your Where clauses just need to contain a Contains criteria and some Not Contains?
if (inhouse == "Inhouse")
r = r.Where(p => p.Contains(inhouse) && !p.Contains("Supplier") && !p.Contains("Group") && !p.Contains("External"));

Sorted.
var r = from p in autocomplete.tblAutoCompletes
where p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText)
select p.ACItem;
if (inhouse != "Inhouse")
r = r.Where(p => p != "Inhouse");
if (supplier != "Supplier")
r = r.Where(p => p != "Supplier");
if (groupw != "Group")
r = r.Where(p => p != "Group");
if (external != "External")
r = r.Where(p => p != "External");
r = r.OrderBy(p => p);
return r.ToArray();
I had to set the exception in quotation marks as the session vlaue was inappropriate and wouldn't have picked out anything from the list.
Thanks to all those contributing and helping me out.

Related

Linq query across 2 datasets while using String.Split

I am trying to check if an entity exists using certain filters. This is what I started with
bool jff = (from fm in dc.FamilyMembers
from f in dc.FamilyInfos
where fm.Family_ID == f.Family_ID && (fm.Last_Name == item.LastName && fm.Birthdate == item.DOB && f.Address1.Split(' ')[0].Contains(addNumber))
select new { fm, f }).Any();
Then I used AsEnumberable
bool jff = (from fm in dc.FamilyMembers.AsEnumberable()
from f in dc.FamilyInfos.AsEnumberable()
where fm.Family_ID == f.Family_ID && (fm.Last_Name == item.LastName && fm.Birthdate == item.DOB && f.Address1.Split(' ')[0].Contains(addNumber))
select new { fm, f }).Any();
It took 3 mins, so I'm guessing this isn't the best way. Can anyone give any suggestions?
Well best way is to do this in the database instead of loading all into memory. Howeverer, a join and a pre-filter should be much more efficient:
var relevantFamilies = dc.FamilyMembers
.Where(fm => fm.Last_Name == item.LastName && fm.Birthdate == item.DOB);
var relevantFamilyInfo =
from fm in relevantFamilies
join fi in dc.FamilyInfos on fm.Family_ID equals fi.Family_ID
select fi;
bool result = relevantFamilyInfo.AsEnumerable() // because you store multiple informations in Address1 you need to execute part of the query in memory, normalize your DB
.Any(info => info.Address1.Split(' ')[0].Contains(addNumber));
EF Core has not translation for Split, but you can emulate first element retrieval:
bool jff = (
from fm in dc.FamilyMembers
from f in dc.FamilyInfos
where fm.Family_ID == f.Family_ID && fm.Last_Name == item.LastName && fm.Birthdate == item.DOB
&& f.Address1.Substring(0, f.Address1.IndexOf(" ")).Contains(addNumber)
select new { fm, f }
).Any();

Linq query where Contains() checks for list of strings

Consider the Following Query:
var query = from o in this.OrderManager.LoadOrders()
join s in this.SkuManager.LoadSkus() on o.SKU equals s.SKU
where o.ORDER_ID == orderId
let parcelItem = o.RPU != "Y" && o.DROP_SHIP != "Y" && s.TRUCK_SHIP != "T" && o.SKU != "ABC-123" && o.SKU != "XYZ-789" && o.SKU != "JKL-456"
select new OrderMailLineItem
{
OrderId = o.ORDER_ID,
Sku = s.SKU,
WarehouseId = s.SITE_ID,
QualifyingItem = qualifyingItem,
OversizedItem = parcelItem && (s.DROP_SHIP == null)
};
I would like to be able to write the line let parcelItem = ... to be more like !o.SKU.Contains(skuList) where:
List<string> skuList = new List<string> { "ABC-123", "XYZ-789", "JKL-456"};
You should check whether SKU is not in list instead of checking whether list is in SKU:
let parcelItem = !skuList.Contains(o.SKU)
!skuList.Contains(o.SKU) is exactly how you'd usually do it.
But you could write an In operator, if you like:
public static class ExtensionMethods
{
public static bool In<T>(this T t, params T[] values)
=> values.Contains(t);
}
...
let parcelItem = o.RPU != "Y" && o.DROP_SHIP != "Y" && s.TRUCK_SHIP != "T" &&
!o.SKU.In("ABC-123", "XYZ-789", "JKL-456")
I doubt that'll work with Linq to SQL though.
I don't see why this wouldn't work. You would just need to check those three Yes/No flags in addition to your SKU list.
var skuList = new[] { "ABC-123", "XYZ-789", "JKL-456"};
var query = from o in this.OrderManager.LoadOrders()
join s in this.SkuManager.LoadSkus() on o.SKU equals s.SKU
where o.ORDER_ID == orderId
let parcelItem = o.RPU != "Y" && o.DROP_SHIP != "Y" && s.TRUCK_SHIP != "T" && skuList.Contains(o.SKU)
select new OrderMailLineItem
{
OrderId = o.ORDER_ID,
Sku = s.SKU,
WarehouseId = s.SITE_ID,
QualifyingItem = qualifyingItem,
OversizedItem = parcelItem && (s.DROP_SHIP == null)
};

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();
}

Using .include(),.where(),.select() for LINQ query

I have a query like this:
var rrx = (from camp in db.Campus
join camproom in db.CampusRooms
on camp.Id equals camproom.CampusId
where (camproom.CampusId == 1) && (camp.BranchId == 10) && (camproom.Status == 0)
select new CampusCampusRoom { CampName = camp.Name, CampusRoomNo = camproom.RoomNo, CampusClassCapacity = camproom.ClassCapacity, CampusExamCapacity = camproom.ExamCapacity }).ToList();
How can I perform this query using .include(), .where(), .select() clauses?
Here is an easy to use filtered projection example. This should provide you with a good example of what you want to do with your query.:
var customersWithRecentReservations =
from c in context.Contacts.OfType<Customer>()
where c.FirstName == p_firstName && c.LastName == p_lastName
select new {Customer = c, Reservations = c.Reservations.Where(r => r.ReservationDate >= p_reservationDate)};
var customers = customersWithRecentReservations.AsEnumerable().Select(p => p.Customer);
Try and adapt this code to your situation or let me know if you need further assistance with it ;)

Cannot implicitly convert type string to string[] in autocomplete method

Afternoon all - it's Friday th 13th so of course I am having an absolute mare!!!
The code below, 'should' create a list of items that will be used in a textbox autocomplete.
public string[] GetAutoComplete(string prefixText, int count)
{
try
{
string memberid = HttpContext.Current.Session["VDS_MemberID"].ToString();
string locationid = HttpContext.Current.Session["VDS_LocationID"].ToString();
string inhouse = HttpContext.Current.Session["VDS_Inhouse"].ToString();
string supplier = HttpContext.Current.Session["VDS_Supplier"].ToString();
string groupw = HttpContext.Current.Session["VDS_Group"].ToString();
string external = HttpContext.Current.Session["VDS_External"].ToString();
VDSORDAL.PDC_VDSOREntities autocomplete = new VDSORDAL.PDC_VDSOREntities();
var r = (from p in autocomplete.tblAutoCompletes
where p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText)
select p);
if (inhouse != "DoNotDisplayInhouse")
r = r.Where(p => p.ACItem == inhouse);
if (supplier != "DoNotDisplaySupplier")
r = r.Where(p => p.ACItem == supplier);
if (groupw != "DoNotDisplayGroup")
r = r.Where(p => p.ACItem == groupw);
if (external != "DoNotDisplayExternal")
r = r.Where(p => p.ACItem == external);
return r.Distinct().OrderBy(p => p.ACItem).ToString();
}
However, I am getting the question title as an error.
Can anyone suggest a way around this? Apologies..I am having a bad day.
Possibly
return r.Distinct().OrderBy(p => p.ACItem).ToString();
should be
return r.Distinct().OrderBy(p => p.ACItem).ToArray();
Update:
Sounds like that's your real problem. Try (following code is brain-compiled)
return (from p in r orderby p.ACItem desc select p.ACItem).ToArray();
I'm assuming ACItem is the string you want to return, if not, select what you want in the array.
Or possibly
return (from p in r where p != null orderby p.ACItem desc select p.ACItem).ToArray();
the where p != null may be necessary, you pretty much need to inspect r and see what's in there, not really enough info to be able to answer this conclusively.
That said, .ToArray instead of .ToString is still the answer to your problem, anything else is a different question.
The last line should be:
return r.Distinct().OrderBy(p => p.ACItem).ToArray();
Don't do a ToString(). Use either ToArray() or ConvertAll<string>().ToArray()

Categories

Resources