LINQ XML C# remove where condition in loop - c#

Trying to delete nodes under certain conditions. Basically if certain checkboxes are checked I give an extra query with WHERE statement to my IENumerable named upit. After the queries has been set im trying to delete them iterating through every one, but nothing gets deleted everytime.
XDocument X = XDocument.Load(#"Financije.xml");
var upit = X.Element("POPIS").Elements("PODACI");
if (mjesec.Checked) { upit = upit.Where(E => (Convert.ToInt32(E.Element("MJESEC").Value) == Convert.ToInt32(mjesecbox.Text))); }
if (godina.Checked) { upit = upit.Where(E => (Convert.ToInt32(E.Element("GODINA").Value) == Convert.ToInt32(godinabox.Text))); }
if (ime.Checked) { upit = upit.Where(E => (E.Element("IME").Value.ToString().ToLower().Contains(search.Text.ToString().ToLower()))); }
if (opis.Checked) { upit = upit.Where(E => (E.Element("OPIS").Value.ToString().ToLower().Contains(search.Text.ToString().ToLower()))); }
if (veceod.Checked) { upit = upit.Where(E => (Convert.ToInt32(E.Element("CIJENA").Value.ToString()) > Convert.ToInt32(iznos.Text.ToString()))); }
if (manjeod.Checked) { upit = upit.Where(E => (Convert.ToInt32(E.Element("CIJENA").Value.ToString()) < Convert.ToInt32(iznos.Text.ToString()))); }
foreach (var item in upit)
{
upit.Remove();
}
and this is my XML file
<?xml version="1.0" encoding="utf-8"?>
<POPIS>
<PODACI>
<IME>test</IME>
<CIJENA>200</CIJENA>
<DATUM>12.1.2019</DATUM>
<MJESEC>1</MJESEC>
<GODINA>2019</GODINA>
<OPIS>test123333</OPIS>
</PODACI>
<PODACI>
<IME>voda</IME>
<CIJENA>230</CIJENA>
<DATUM>12.4.2018</DATUM>
<MJESEC>4</MJESEC>
<GODINA>2018</GODINA>
<OPIS>yes123no</OPIS>
</PODACI>
<PODACI>
<IME>oops</IME>
<OPIS>nice</OPIS>
<CIJENA>3</CIJENA>
<MJESEC>5</MJESEC>
<GODINA>2018<GODINA/>
<DATUM>24.02.2019</DATUM>
</PODACI>
<PODACI>
<IME>test</IME>
<OPIS>123</OPIS>
<CIJENA>1</CIJENA>
<MJESEC>12</MJESEC>
<GODINA>2019<GODINA/>
<DATUM>24.02.2019</DATUM>
</PODACI>
</POPIS>

It's a bit unclear what you want to end up with, but I assume you want to exclude items where they fail at least one case where the checkbox is checked and that comparison you are doing fails. So below achieves it in one query:
var X = XDocument.Load("Financije.xml");
var upit = X.Element("POPIS").Elements("PODACI");
var toRemove = upit.Where(u =>
// If mjesec is not checked, skip the predicate, otherwise evaluate it.
(!mjesec.Checked || (Convert.ToInt32(u.Element("MJESEC").Value) == Convert.ToInt32(mjesecbox.Text)))
// *And* do the same for godina and the rest of checkboxes...
&& (!godina.Checked || (Convert.ToInt32(u.Element("GODINA").Value) == Convert.ToInt32(godinabox.Text)))
&& (!ime.Checked || (u.Element("IME").Value.ToString().ToLower().Contains(search.Text.ToString().ToLower())))
&& (!opis.Checked || (u.Element("OPIS").Value.ToString().ToLower().Contains(search.Text.ToString().ToLower())))
&& (!veceod.Checked || (Convert.ToInt32(u.Element("CIJENA").Value.ToString()) > Convert.ToInt32(iznos.Text.ToString())))
&& (!manjeod.Checked || (Convert.ToInt32(u.Element("CIJENA").Value.ToString()) < Convert.ToInt32(iznos.Text.ToString()))));
X.Element("POPIS").ReplaceAll(upit.Except(toRemove));
X.Save("Financije.xml");

Give it a try
XDocument X = XDocument.Load(#"Financije.xml");
var upit = X.Element("POPIS").Elements("PODACI");
//I‘m only on phone so please excuse, if I take the wrong Type. Assign to null, to prevent Compiler-Error
IEnumerable<XElement> upitPart= null;
if (mjesec.Checked) { upitPart = upit.Where(E => (Convert.ToInt32(E.Element("MJESEC").Value) == Convert.ToInt32(mjesecbox.Text))); }
if (godina.Checked) { upitPart = upitPart.Where(E => (Convert.ToInt32(E.Element("GODINA").Value) == Convert.ToInt32(godinabox.Text))); }
if (ime.Checked) { upitPart = upitPart.Where(E => (E.Element("IME").Value.ToString().ToLower().Contains(search.Text.ToString().ToLower()))); }
if (opis.Checked) { upitPart = upitPart.Where(E => (E.Element("OPIS").Value.ToString().ToLower().Contains(search.Text.ToString().ToLower()))); }
if (veceod.Checked) { upitPart = upitPart.Where(E => (Convert.ToInt32(E.Element("CIJENA").Value.ToString()) > Convert.ToInt32(iznos.Text.ToString()))); }
if (manjeod.Checked) { upitPart = upitPart.Where(E => (Convert.ToInt32(E.Element("CIJENA").Value.ToString()) < Convert.ToInt32(iznos.Text.ToString()))); }
if(upitPart != null)
{
foreach (var item in upitPart)
{
upit.Remove(item);
}
}

Related

Getting System.StackOverflowException , in a recursive function call?

I have to two function which is used to find tags inside the tags like, there is a tag A=B(C(D(E))) so i have to find all the tags inside B then all the tags inside C and so on. I write two function but getting the error System.StackOverflowException. In the first function i am providing the tag ID and against that tag id i am getting getNestesCalTagsId and then calling the getNestedCalTagsIngredients() function. But when there are lot of recursion calls i get the error System.StackOverflowException. Below is my whole code.
public List<int?> getNestedCalTags(int? calTagId)
{
var getNestesCalTagsId = db.Dependencies_Metrix.Where(x => x.Cal_Tag_P_Id == calTagId && x.Status == true && x.Cal_Tag_Id_FK!=null).Select(x => x.Cal_Tag_Id_FK).ToList();
if (getNestesCalTagsId.Count > 0)
{
nestedCalFTags.AddRange(getNestesCalTagsId);
foreach (var item in getNestesCalTagsId)
{
if (item != null)
{
getNestedCalTagsIngredients(item.Value);
}
}
}
if (nestedCalFTags.Count > 0)
{
int countedTags = nestedCalFTags.Count;
List<int?> tags = new List<int?>(nestedCalFTags);
for (int i = 0; i < tags.Count; i++)
{
if (tags[i] != null)
{
getNestedCalTagsIngredients(tags[i].Value);
}
}
}
return nestedRawTags;
}
public bool getNestedCalTagsIngredients(int nestCalTagId)
{
var getCalTags = db.Dependencies_Metrix.Where(x => x.Cal_Tag_P_Id == nestCalTagId && x.Status == true).ToList();
if (getCalTags.Count > 0)
{
foreach (var item in getCalTags)
{
if (item.Cal_Tag_Id_FK != null)
{
var getNestedCalTagParent = db.Dependencies_Metrix.Where(x => x.Cal_Tag_P_Id == item.Cal_Tag_Id_FK && x.Status == true && x.Cal_Tag_Id_FK!=null).Select(x => x.Cal_Tag_Id_FK).ToList();
if (getNestedCalTagParent != null)
{
nestedCalFTags.AddRange(getNestedCalTagParent);
getNestedCalTags(item.Cal_Tag_Id_FK);
}
}
else
{
var rawTagId = db.Dependencies_Metrix.Where(x => x.Cal_Tag_P_Id == item.Cal_Tag_P_Id && x.Real_Tag_Id_FK!=null).Select(x => x.Real_Tag_Id_FK).ToList();
if (rawTagId != null)
{
foreach (var rawItem in rawTagId)
{
if (rawItem!=null)
{
if (nestedRawTags.IndexOf(rawItem.Value) == -1)
{
nestedRawTags.Add(rawItem.Value);
}
}
}
}
nestedCalFTags.Remove(nestCalTagId);
}
}
}
return true;
}

LINQ "OR" in expression

Just trying to get a cleaner code on a delete method. I need to delete records from a database if a certain column value matches one of two columns in another table.
Is there a better way to delete multiple records, with a "OR"-like expression, so that I can have only one for each loop instead of the following two?
public static void DeleteStageById(int StageId, int ApplicationId)
{
using (IPEntities ip = IPEntities.New())
{
var stage = ip.mkStages;
var stageCultures = ip.appObjectCultures;
var stageStates = ip.mkStatesInStages;
foreach (var stageCulture in stageCultures.Where(sC => sC.ObjectCultureId == stage.Where(s => s.StageId == StageId && s.ApplicationId == ApplicationId).FirstOrDefault().OCId_Name))
{
stageCultures.DeleteObject(stageCulture);
}
foreach (var stageCulture in stageCultures.Where(sC => sC.ObjectCultureId == stage.Where(s => s.StageId == StageId && s.ApplicationId == ApplicationId).FirstOrDefault().OCId_Description))
{
stageCultures.DeleteObject(stageCulture);
}
...
ip.SaveChanges();
}
}
my linq would look like this one
var stage = ip.mkStages;
var stageCultures = ip.appObjectCultures;
var stageStates = ip.mkStatesInStages;
//store this result into a temp variable so it only needs to run once
var temp = stage.Where(s => s.StageId == StageId && s.ApplicationId == ApplicationId).FirstOrDefault();
if (temp != null)
{
foreach (var stageCulture in stageCultures.Where(sC => sC.ObjectCultureId == temp.OCId_Name || sC.ObjectCultureId == temp.OCId_Description))
{
stageCultures.DeleteObject(stageCulture);
}
...
ip.SaveChanges();
}
I recommend avoiding confusing expressions, but here you go:
foreach (var stageCulture in stageCultures.Where(sC => {
var v = stage.Where(s => s.StageId == StageId && s.ApplicationId == ApplicationId).FirstOrDefault();
return sC.ObjectCultureId == v.OCId_Name || sC.ObjectCultureId == v.OCId_Description;
})
{
stageCultures.DeleteObject(stageCulture);
}

Dynamic Linq Build Where Clause many Parameters

I will explain my Problem
so Firstly, I use Predicates Linq for Build Where clause dynamically.
I have to build dynamically because I don't know how many parameters will come. Let me give an example. For the A column can be one parameters however, for the B column can be 2 parameters like either value 'Gas' or 'Oil' which select but that's big problem I can not combine for these 2 column correctly.
So as a result, this code work but It return 0 Items. But there are I know.
public List<CarEntity> GetSearchByKCriteria(int cityId, List<string> fuelType, List<string> gearType, List<string> budget,
List<string> caroser, List<string> enginePower)
{
Expression<Func<Car, bool>> query = null;
Expression<Func<Car, bool>> combine = null;
foreach (var bud in budget)
{
if (budget.Count >= 1)
{
if (bud == "1")
{
if (budget.Count > 1)
{
query = car => car.Budget >= 20000 && car.Budget <= 34999;
}
else
{
query = car => car.Budget >= 20000 && car.Budget <= 34999;
}
}
else if (bud == "2")
{
if (query != null)
{
combine = car => (car.Budget >= 35000 && car.Budget <= 49999);
query = query.Or(combine);
}
else
{
query = car => car.Budget >= 35000 && car.Budget <= 49999;
}
}
}
}
foreach (var caros in caroser)
{
if (caros != "-1" && !string.IsNullOrEmpty(caros))
{
if (query != null)
{
if (query.Expand().ToString().ToLower().Contains("karoser"))
{
combine = car => (car.Karoser == caros);
query = query.And(combine);
}
else
{
combine = car => car.Karoser == caros;
query = query.And(combine);
}
}
else
{
query = car => car.Karoser == caros;
}
}
}
foreach (var fuel in fuelType)
{
if (fuel != "-1" && !string.IsNullOrEmpty(fuel))
{
if (query != null)
{
if (query.Expand().ToString().ToLower().Contains("yakituru"))
{
combine = car => (car.YakitTuru==fuel);
query = query.Or(combine);
}
else
{
combine = car => car.YakitTuru == fuel;
query = query.And(combine);
}
}
else
{
query = car => car.YakitTuru == fuel;
}
}
}
foreach (var gear in gearType)
{
if (gear!="-1"&& !string.IsNullOrEmpty(gear))
{
if (query != null)
{
if (query.Expand().ToString().ToLower().Contains("sanzimantipi"))
{
combine = car => (car.SanzimanTipi == gear);
query = query.Or(combine);
}
else
{
combine = car => car.SanzimanTipi == gear;
query = query.And(combine);
}
}
else
{
query = car => car.SanzimanTipi == gear;
}
}
}
foreach (var engine in enginePower)
{
if (enginePower.Count >= 1)
{
if (engine == "1")
{
if (query != null)
{
if (query.Expand().ToString().ToLower().Contains("silindirhacmi"))
{
combine = car => (car.SilindirHacmi >= 0 && car.SilindirHacmi <= 1600);
query = query.Or(combine);
}
else
{
combine = car => (car.SilindirHacmi >= 0 && car.SilindirHacmi <= 1600);
query = query.And(combine);
}
}
else
{
query = car => car.SilindirHacmi >= 0 && car.SilindirHacmi <= 1600;
}
}
if (engine == "3")
{
if (query != null)
{
if (query.Expand().ToString().ToLower().Contains("silindirhacmi"))
{
combine = car => (car.SilindirHacmi >= 1601 && car.SilindirHacmi <= 1800);
query = query.Or(combine);
}
else
{
combine = car => (car.SilindirHacmi >= 1601 && car.SilindirHacmi <= 1800);
query = query.And(combine);
}
}
else
{
query = car => car.SilindirHacmi >= 1601 && car.SilindirHacmi <= 1800;
}
}
}
using (var context = DataContextFactory.CreateContext())
{
var result = (from fkCar in context.Car.Where(query)
join pkCarBrand in context.CarBrand on fkCar.Marka equals pkCarBrand.ID
where fkCar.IsActive == true
select new
{
entity = fkCar,
joinEntity = pkCarBrand
});
List<CarEntity> theCarList = new List<CarEntity>();
foreach (var item in result)
{
CarEntity theEntity = Mapper.Map(item.entity);
theEntity.CarBrand = Mapper.Map(item.joinEntity);
theCarList.Add(theEntity);
}
return theCarList;
}
}
So thanks for reply,
I faced a similar challenge a while back, where I wanted to have a list of allowed values for an attribute where, if matched, the associated instance would pass the filter. I came up with the following extension method:
static public Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
{
if (null == valueSelector)
{
throw new ArgumentNullException("valueSelector");
}
if (null == values) { throw new ArgumentNullException("values"); }
ParameterExpression p = valueSelector.Parameters.Single();
if (!values.Any())
{
return e => false;
}
var equals = values.Select(value => (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));
var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));
return Expression.Lambda<Func<TElement, bool>>(body, p);
}
This is based on the discussion and code posted at http://www.velocityreviews.com/forums/t645784-linq-where-clause.html

Convert if else to linq

I have following code in c# in which I am searching for lowest price flight .Now I want to convert it to Linq
for (; count < _flightSearchController.ListOfContracts.Count; count++)
{
contract = (DTContract)_flightSearchController.ListOfContracts[count];
if (contract.CurrentStatus == AvailabilityStatus.AVAILABLE)
{
if (CheckContractCitiesWithSearchCriteria(contract, originAirports, destinationAirports))
{
//if fare is lower than selected contract.
if (lowestPriceContract == null || lowestPriceContract.FareDetails.PriceForDefaultFlightSelection > contract.FareDetails.PriceForDefaultFlightSelection)
{
lowestPriceContract = contract;
}
else if (lowestPriceContract.FareDetails.PriceForDefaultFlightSelection == contract.FareDetails.PriceForDefaultFlightSelection)
{
if (lowestPriceContract.FareDetails.PriceAdult > 0 && (lowestPriceContract.FareDetails.PriceAdult + lowestPriceContract.FareDetails.FareTaxAdult) > (contract.FareDetails.PriceAdult + contract.FareDetails.FareTaxAdult))
{
lowestPriceContract = contract;
}
else if (lowestPriceContract.FareDetails.PriceSenior > 0 && (lowestPriceContract.FareDetails.PriceSenior + lowestPriceContract.FareDetails.FareTaxSenior) > (contract.FareDetails.PriceSenior + contract.FareDetails.FareTaxSenior))
{
lowestPriceContract = contract;
}
}
}
}
I tried it to convert but stuck in if else if section.
var q = _flightSearchController.ListOfContracts.ToList<DTContract>()
.Where(cont => cont.CurrentStatus == AvailabilityStatus.AVAILABLE);
if (lowestPriceContract == null || lowestPriceContract.FareDetails.PriceForDefaultFlightSelection > contract.FareDetails.PriceForDefaultFlightSelection)
{
}
Use the Min extension method:
var q = _flightSearchController.ListOfContracts
.Where(cont => cont.CurrentStatus == AvailabilityStatus.AVAILABLE
&& CheckContractCitiesWithSearchCriteria(cont, originAirports, destinationAirports))
.Min(cont=> cont.FareDetails.PriceForDefaultFlightSelection)
Edit I had glossed over the tie-breaker part, which makes it a bit more complicated. You can do it with sorting, but this will be slower when there are a lot of contracts:
var q = _flightSearchController.ListOfContracts
.Where(cont => cont.CurrentStatus == AvailabilityStatus.AVAILABLE)
&& CheckContractCitiesWithSearchCriteria(cont, originAirports, destinationAirports))
.OrderBy(cont => FareDetails.PriceForDefaultFlightSelection)
.ThenBy(cont => cont.FareDetails.PriceAdult + lowestPriceContract.FareDetails.FareTaxAdult)
.ThenBy(cont => cont.FareDetails.PriceSenior + lowestPriceContract.FareDetails.FareTaxSenior)
.First();
You could implement the IComparable interface for the FareDetails object to compare the prices, which would allow you to do this:
var q = _flightSearchController.ListOfContracts
.Where(cont => cont.CurrentStatus == AvailabilityStatus.AVAILABLE
&& CheckContractCitiesWithSearchCriteria(cont, originAirports, destinationAirports))
.Min(cont=> cont.FareDetails)

optimising linq queries to incres

I have the the below linq queries searching a the same data table and was wondering if it would be possible to make one search and do the below for loops to add data to to the same variables so that it can make the system faster.
var sort = configurationData.AsEnumerable().Where(sorts => sorts.Field<String>("QuestionStartText") == question &&
sorts.Field<String>("slideNo") == Convert.ToString(slideNumber) )
.Select(sorted => sorted.Field<String>("SortByColumn")).Distinct().AsParallel();
var rowNeedAfterSort = configurationData.AsEnumerable().Where(sorts => sorts.Field<String>("QuestionStartText") == question &&
sorts.Field<String>("slideNo") == Convert.ToString(slideNumber))
.Select(sorted => sorted.Field<String>("NoOfRows")).Distinct().AsParallel();
var indexs = configurationData.AsEnumerable().Where(sorts => sorts.Field<String>("QuestionStartText") == question &&
sorts.Field<String>("slideNo") == Convert.ToString(slideNumber))
.Select(sorted => sorted.Field<String>("ColumnInExcel")).Distinct().AsParallel();
int p = 0;
int chartValue = 0;
foreach (string inedcies in indexs)
{
if (inedcies != null)
{
if (!inedcies.ToUpper().Equals("NULL"))
{
if (inedcies.Contains(','))
{
Array.Clear(valuesUsed, 0, valuesUsed.Length);
string[] index = inedcies.Split(',');
foreach (string a in index)
{
valuesUsed[p] = Convert.ToInt32(a);
p++;
}
}
else if (inedcies.Equals("7"))
{
Array.Clear(valuesUsed, 0, valuesUsed.Length);
valuesUsed[p] = Convert.ToInt32(inedcies);
}
else
{
chartValue = Convert.ToInt32(inedcies);
}
}
}
}
foreach (string sortedint in sort)
{
if (sortedint != null)
{
if (!sortedint.ToUpper().Equals("NULL"))
{
SortData2(sortedint);
sortedData = "true";
}
}
}
foreach (string rows in rowNeedAfterSort)
{
if (rows != null)
{
if (!rows.ToUpper().Equals("NULL"))
{
string[] values = rows.Split(' ');
rowCount = Convert.ToInt32(values[1]);
}
}
}
Once you clean up the below codesmell you will be able to see how/where you can take out the foreach loops.
foreach (string a in index)
{
valuesUsed[p] = Convert.ToInt32(a);
p++;
}
what assurances do we have that index.length < valuesUsed.length ?
Foreach (x in y)
{
if (x != null)
{
do something
}
}
More readable. You also do not need to check if an element is null in a foreach loop. The properties of the element may need to be checked, but not the element itself.
y.Foreach(x => do what you need here)

Categories