How do you findIndex with conditionals like && - c#

Let's say you have a List l_mur = new List();
And you populate the list.
Then based on conditions you want to REMOVE some values without requerying...
l_mur.RemoveAt(l_mur.FindIndex(f => (f.xid == tmur.xid && f.sid == tmur.sid && f.mid == tmur.mid && f.bid == tmur.bid)));
However, the code I used here, does not seem to work. It tells me index out of range, but how can it be out of range if I am just searching for something that truly does exist.

List<T>.FindIndex() returns -1 in case there is no match found - which is out of range for List<T>.RemoveAt().
Also note that FindIndex() only returns the index of the first occurrence based on your predicate - if there is more than one match you will only be able to delete the first one of them with your current approach.
A better approach to delete in place based on a predicate would be RemoveAll():
l_mur.RemoveAll(f => (f.xid == tmur.xid && f.sid == tmur.sid && f.mid == tmur.mid && f.bid == tmur.bid));

May be a good idea is to filter the list to a new instance of the list:
var l_mur = l_mur.Where(f => (f.xid != tmur.xid || f.sid != tmur.sid || f.mid != tmur.mid || f.bid != tmur.bid));

Use this code:
l_mur.Remove(l_mur.Find(f => (f.xid == tmur.xid && f.sid == tmur.sid && f.mid == tmur.mid && f.bid == tmur.bid)));

Related

C# Linq to EF Separate Subquery into Expression

I have a complex where clause in my EF linq statement which repeats a subquery expression, on _db.OPESRRecoveryElements, but with different parameters, one of which is depending on records from the main entity, OPCases/OPCaseDto.
The query as it is works, but its hard for people to read. Ideally I'd like to be able to create an expression which could be re-used at the 3 necessary points and would still allow it to execute as a single, server-side SQL statement.
Is there a way to create an Expression / IQueryable definition which can be used for a subquery like this?
List<OPCaseDto> opCases = await _db.OPCases
.ProjectTo<OPCaseDto>(_autoMapperConfig, null, requestedExpands)
.Where(c =>
c.OPStatusId == OPStatusIds.AwaitingRecoveryElement
&& (
(c.OPCategoryLetter == "B"
// Only need a gross pensionable element if there is an outstanding gross pensionable figure
&& (c.GrossOverpaidPensionable - c.GrossRecoveredPensionable == 0
|| _db.OPESRRecoveryElements.Any(e => !e.NonPensionable && e.OPRecoveryMethod.OPTypeLetter == "G"
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery)
&& rp.AssignmentNo == c.RecoveryAssignmentNo)))
// Only need a gross non-pensionable element if there is an outstanding gross non-pensionable figure
&& (c.GrossOverpaidNonPensionable - c.GrossRecoveredNonPensionable == 0
|| _db.OPESRRecoveryElements.Any(e => e.NonPensionable && e.OPRecoveryMethod.OPTypeLetter == "G"
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery)
&& rp.AssignmentNo == c.RecoveryAssignmentNo))))
|| (c.OPCategoryLetter == "D"
// Don't need to check for an outstanding net figure - if the case is net and isn't complete, there will be one!
&& _db.OPESRRecoveryElements.Any(e => e.OPRecoveryMethod.OPTypeLetter == "N"
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery)
&& rp.AssignmentNo == c.RecoveryAssignmentNo)))
)
)
.AsNoTracking()
.ToListAsync();
If it wasn't for the c.RecoveryAssignmentNo part, I could easily create an expression like:
public Expression<Func<OPESRRecoveryElement, bool>> NoActiveRecoveryPlans(string opType, bool nonPen)
{
return e => e.OPRecoveryMethod.OPTypeLetter == opType
&& e.NonPensionable == nonPen
&& !e.OPRecoveryPlans.Any(rp
=> (rp.RecoveryStatus == OPRecoveryStatuses.NotStarted || rp.RecoveryStatus == OPRecoveryStatuses.InRecovery));
}
and use it like:
(c.OPCategoryLetter == "B"
// Only need a gross pensionable element if there is an outstanding gross pensionable figure
&& (c.GrossOverpaidPensionable - c.GrossRecoveredPensionable == 0
|| _db.OPESRRecoveryElements.Any(NoActiveRecoveryPlans("G", false)))
and it would get executed before the query to get the OPCases.
I could also fetch all the OPCaseDto records and OPESRRecoveryElements as separate queries and filter in memory, but I don't want to do that.
If I add a parameter to the function, string assignmentNo, I (unsurprisingly) get an error - "Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpression3' to type 'System.Linq.Expressions.LambdaExpression'"

This function can only be invoked from LINQ to Entities. .All()

I have a List property that I am setting like so:
testCard.LstSummaries =
db.Summaries.Where(
x =>
(x.AID == aId || x.AInformation.RegNumber == aRegNumber) && DbFunctions.TruncateTime(x.Day) == DateTime.Today.Date &&
x.deleted == false).ToList();
Then I have a conditional statement:
if (testCard.LstSummaries.Count > 0)
{
if (
testCard.LstSummaries.All(
x =>
(x.AID == aId || // ERROR HAPPENS ON THIS LINE
x.AInformation.RegNumber == aRegNumber) &&
DbFunctions.TruncateTime(x.Day) == DateTime.Today.Date && x.deleted == false))
{
// .... do something
}
I get an error:
This function can only be invoked from LINQ to Entities.
I want to avoid to make multiple calls to the database.. furthermore testCard.LstSummaries already has the values I am looking for.. but if I do this:
if (testCard.LstSummaries.Count > 0)
{
if (
db.Summaries.All(
x =>
(x.AID == aId || // NO ERROR
x.AInformation.RegNumber == aRegNumber) &&
DbFunctions.TruncateTime(x.Day) == DateTime.Today.Date && x.deleted == false))
{
// .... do something
}
I feel like making this call to the database is pointless because I would be retrieving the same results that are already stored in testCard.LstSummaries, but I can't invoke .All() because it's not LINQ to Entities.
Is there a workaround for this?
Problem is with DbFunctions.TruncateTime(x.Day), because it is converted to sql on runtime. Try to check without it.

LINQ doesnt work for japanese words

I have list of items defined as: IQueryable and I need go trough and find if any of the fields contain a specific word. When I use foreach and loop trough it and use .Contains, then everything works fine. The problem is that I need to use LINQ and .Boost, because some of the fields have higher priority when I find words in them.
When I use LINQ I get no results. For most languages LINQ works fine, but for Japanese words it does not. Can someone explain me why foreach with .Contains works fine and LINQ with .Where does not?
Code example:
foreach (var item in itemList)
{
if ((item.PageHeadings != null && item.PageHeadings.Contains(keyword)) ||
(item.PageName != null && item.PageName.Contains(keyword)) ||
(item.MetadataDescription != null &&
item.MetadataDescription.Contains(keyword)) ||
(item.MetadataKeywords != null &&
item.MetadataKeywords.Contains(keyword)) ||
(item.ExpandedContent != null &&
item.ExpandedContent.Contains(keyword)))
{
list.Add(item.Name);
}
}
LINQ example:
list.AddRange(from item in itemList where (item.PageHeadings != null
&& item.PageHeadings.Contains(keyword).Boost(BoostPageHeading))
|| (item.PageName != null && item.PageName.Contains(keyword).Boost(BoostPageName))
|| (item.MetadataDescription != null && item.MetadataDescription.Contains(keyword).Boost(BoostMetadataDescription))
|| (item.MetadataKeywords != null && item.MetadataKeywords.Contains(keyword).Boost(BoostMetadataKeywords))
|| (item.ExpandedContent != null && item.ExpandedContent.Contains(keyword).Boost(BoostExpandedContent)) select item.Name);
Thanks
UPDATE:
Example of phrase: 天窓使用例

|| ,| , && inside an IF statement

i want to do the following IF statement,
if (checkID.Equals(Convert.ToInt32(txtCheck.Text))
&& drop == 319020000
|| currentFloor[id][0].checkFlag == 1)
what i want to check here it the following thing:
i want to check if this whole statement is true
checkID.Equals(Convert.ToInt32(txtCheck.Text)) && drop == 319020000`
or this statment:
currentFloor[id][0].checkFlag == 1
If 1 of them is true it should go inside the loop.
What am i doing wrong here?
Use parentheses, you have many operators at the same level and precedence may be killing you
if ((checkID.Equals(Convert.ToInt32(txtCheck.Text)) && drop == 319020000)
|| currentFloor[id][0].checkFlag == 1)
http://msdn.microsoft.com/en-us/library/aa691323(v=vs.71).aspx
;)
you have to use additional parentheses like follows,
if ((checkID.Equals(Convert.ToInt32(txtCheck.Text)) && drop == 319020000) || currentFloor[id][0].checkFlag == 1)

how to combine textbox values in a linq query?

I have a page in which I have several textboxes in order to search depending the value of the textboxes,If I make the search eith only one value everithing works fine but if I try to combine 2 or more values I only get the result of the last textbox.
Here's my query hope you could help me.
var query = from m in SolContext.Menores
where ((m.Solicitud.fiIdSolicitud == rdTxtFolio.Value) || (m.Solicitud.fiAnioSolicitud == rdTxtAnioFolio.Value)
|| (m.Solicitud.CTEdoSolicitud.fcDescEdoSol == status) || (m.Solicitud.fiCircuito == cto) || (m.Solicitud.fiCiudad == cd)
|| (m.Solicitud.fcCveAdsc == adsc) || (m.Solicitud.fiExpEmpleado == rdTxtExp.Value) || (m.Solicitud.fcNomEmpleado == rdTxtNom.Text)
|| (m.Solicitud.fcPatEmpleado == rdTxtAPat.Text) || (m.Solicitud.fcMatEmpleado == rdTxtAMat.Text) || (m.fcPatMenor == rdTxtAPatMenor.Text)
|| (m.fcMatMenor == rdTxtAmatMenor.Text) || (m.fcNomMenor == rdTxtNomMenor.Text) || (m.fiSexoMenor == sexo) || (m.fiAnosMenor == rdTxtAniosMenor.Value) || (m.fiMesesMenor == rdTxtMesMenor.Value))
select m;
rgSolic.DataSource = query;
rgSolic.Rebind();
My guess is that the result of the first textbox is included in the result of the second one.
My guess is that you're using or. The first textbox that matches your value will end your search. If you want to check if it matches all your values, use and.
If that doesn't solve it, we'll need more info.

Categories