I am trying to update a property on each object within an array of objects with the value of a property on another object (MyObject). I am unclear if calling:
my_objects_collection = m_database.GetCollection(MY_OBJECTS_COLLECTION_NAME);
has any performance implications, so I tried calling it only once and executing a new Find command against it (with a modified filter for each iteration) within a For... Loop, see below:
MyObject my_object = null;
IMongoCollection<MyObject> my_objects_collection = null;
if (objects != null)
{
my_objects_collection = m_database.GetCollection<MyObject>(MY_OBJECTS_COLLECTION_NAME);
for (int i = 0; i < objects.Count; i++)
{
Expression<Func<MyObject, bool>> filter = x => (x.ID == objects[i].ID) && (x.LanguageCode == language_code);
my_object = await my_objects_collection.Find(filter).FirstOrDefaultAsync();
if (my_object != null)
{ objects[i].DisplayName = my_object.Name; }
}
}
However, the code above throws the following exception:
Value cannot be null.
Parameter name: collection
at MongoDB.Driver.Core.Misc.Ensure.IsNotNull[T](T value, String paramName)
at MongoDB.Driver.IMongoCollectionExtensions.Find[TDocument](IMongoCollection1 collection, Expression1 filter, FindOptions options)
If I move the my_objects_collection assignment inside the for loop, so that it is called for each iteration, the code works without throwing any exceptions.
Therefore my question is, what happens to the MongoCollection reference (my_objects_collection) after the Find (or any other operation) is executed against it?
I would really appreciated if anyone could provide some insight into this. I could move on since my application is working, but I really want to know why it throws an exception indicating that the collection is null for my own understanding.
Thank you in advance,
Andrew
Regardless of your exception, you do not need to perform a find for each individual record you retrieve, you could achieve this using the $in operator.
You could then loop the resultset and perform your update on each document. This is far more efficient as you are performing a single operation against the database to return your records, and then one for each update. Instead of one for each retrieval and one for each update.
See
Builders<MyObject>.Filter.In
Also if you want to match elements in an embedded array you could use
Builders<MyObject>.Filter.ElemMatch
A quick (untested) example
if (objects != null)
{
var my_objects_collection = m_database.GetCollection<MyObject>(MY_OBJECTS_COLLECTION_NAME);
var filterBuilder = Builders<MyObject>.Filter;
var inFilter = filterBuilder.In(x => x.ID, objects.Select(x => x.ID));
var andFilter = filterBuilder.And(
inFilter,
filterBuilder.Eq(x => x.LanguageCode, language_code)
);
var results = await my_objects_collection.Find(andFilter).ToListAsync();
foreach(var result in results)
{
//result is going to the a database object returns which matched your filter
}
}
Related
I have a method that generates a set of options for a floating drop-down menu. The method is of type IEnumerable<FloatMenuOption>.
When I return the values as a List, it works fine. But when I yield them one by one, every item runs the useAct lambda for the last one yielded, even though they all have correct labels.
Can anyone explain why this might happen? Why would returning a List instead of yielding the items one by one matter?
public override IEnumerable<FloatMenuOption> GetFloatMenuChoicesFor(Pawn myPawn)
{
List<FloatMenuOption> options = new List<FloatMenuOption>();
foreach ( Communicable commTarget in GetCommTargets() )
{
var localCommTarget = commTarget;
System.Action useAct = () =>
{
Job openJob = new Job();
openJob.commTarget = localCommTarget;
myPawn.MindHumanoid.TakeOrderedJob(openJob);
};
options.Add( new FloatMenuOption(localCommTarget.GetLabel(), useAct) );
}
return options;
//Simply commenting out the above line and uncommenting the two below causes the error
// foreach (var opt in options)
// yield return opt;
}
In either case, the options come out with correct labels (from localCommTarget.GetLabel()). However, if yielded, they all do the useAct lambda configured for the last item in the list, while if returned as a list they each do their own useAct lambda.
Why?
Take a look at Captured variable in a loop in C#
I believe if you change your for loop to:
foreach (var opt in options)
{
var capturedOpt = opt;
yield return capturedOpt;
}
you'll be golden.
In your implementation, if your code yields the results instead of adding them to the list, only the last assignment to localCommTarget is used. The reason for this is the fact that the execution of the lambda expression is deferred to the actual access to the return. In other words, the order of execution is different for the different return strategies.
I have a LINQ query like so:
var Item = (from s in contextD.Items where s.Id == Id select s).ToList();
Further down the Item object properties are set like so:
Item.FirstOrDefault().Qty = qtyToUpdate;
Item.FirstOrDefault().TotalPrice = UItem.FirstOrDefault().Qty * UItem.FirstOrDefault().Price;
...
My question is, will calling FirstOrDefault always loop through the result set returned by the query?
Shouldn't a single call be made and put in an object like so:
MyObject objMyObject = new MyObject;
objMyObject = Item.FirstOrDefault();
and then go about setting objMyObject properties.
The first part using FirstOrDefault is actually in the production, I am trying to find out if that's the right way.
Regards.
will calling FirstOrDefault always loop through the result set
returned by the query?
FirstOrDefault() never loops through all result set - it either returns first item, or default if set is empty. Also in this particular case even enumerator will not be created - thus you are calling FirstOrDefault() on variable of List<T> type, simply item at index 0 will be returned (if list is not empty). If you will investigate Enumerable.FirstOrDefault() implementation:
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
if (list.Count > 0)
{
return list[0];
}
}
But this will be invoked each time you are calling FirstOrDefault().
Also you are missing 'default' case. If you are chaining methods like in your first sample, you can get NullReferenceException if list is empty. So, make sure something was returned by query:
var item = Item.FirstOrDefault();
if (item == null)
return; // or throw
item.Qty = qtyToUpdate;
var uitem = UItem.FirstOrDefault();
if (uitem == null)
return; // or throw
item.TotalPrice = uitem.Qty * uitem.Price;
One more note - you have little difference in performance if you are performing FirstOrDefault() on in-memory collection. But difference will be huge if you will perform it without saving query results into list. In that case each FirstOrDefault() call will cause new database query.
While searching for an answer to this question, I've run into similar ones utilizing LINQ but I haven't been able to fully understand them (and thus, implement them), as I'm not familiarized with it. What I would like to, basically, is this:
Check if any element of a list contains a specific string.
If it does, get that element.
I honestly don't know how I would go about doing that. What I can come up with is this (not working, of course):
if (myList.Contains(myString))
string element = myList.ElementAt(myList.IndexOf(myString));
I know WHY it does not work:
myList.Contains() does not return true, since it will check for if a whole element of the list matches the string I specified.
myList.IndexOf() will not find an occurrence, since, as it is the case again, it will check for an element matching the string.
Still, I have no clue how to solve this problem, but I figure I'll have to use LINQ as suggested in similar questions to mine. That being said, if that's the case here, I'd like for the answerer to explain to me the use of LINQ in their example (as I said, I haven't bothered with it in my time with C#). Thank you in advance guys (and gals?).
EDIT: I have come up with a solution; just loop through the list, check if current element contains the string and then set a string equal to the current element. I'm wondering, though, is there a more efficient way than this?
string myString = "bla";
string element = "";
for (int i = 0; i < myList.Count; i++)
{
if (myList[i].Contains(myString))
element = myList[i];
}
You should be able to use Linq here:
var matchingvalues = myList
.Where(stringToCheck => stringToCheck.Contains(myString));
If you simply wish to return the first matching item:
var match = myList
.FirstOrDefault(stringToCheck => stringToCheck.Contains(myString));
if(match != null)
//Do stuff
The basic answer is: you need to iterate through loop and check any element contains the specified string.
So, let's say the code is:
foreach(string item in myList)
{
if(item.Contains(myString))
return item;
}
The equivalent, but terse, code is:
mylist.Where(x => x.Contains(myString)).FirstOrDefault();
Here, x is a parameter that acts like "item" in the above code.
string result = myList.FirstOrDefault(x => x == myString)
if(result != null)
{
//found
}
for (int i = 0; i < myList.Length; i++)
{
if (myList[i].Contains(myString)) // (you use the word "contains". either equals or indexof might be appropriate)
{
return i;
}
}
Old fashion loops are almost always the fastest.
If you want a list of strings containing your string:
var newList = myList.Where(x => x.Contains(myString)).ToList();
Another option is to use Linq FirstOrDefault
var element = myList.Where(x => x.Contains(myString)).FirstOrDefault();
Keep in mind that Contains method is case sensitive.
You could use Linq's FirstOrDefault extension method:
string element = myList.FirstOrDefault(s => s.Contains(myString));
This will return the fist element that contains the substring myString, or null if no such element is found.
If all you need is the index, use the List<T> class's FindIndex method:
int index = myList.FindIndex(s => s.Contains(myString));
This will return the the index of fist element that contains the substring myString, or -1 if no such element is found.
Many good answers here, but I use a simple one using Exists, as below:
foreach (var setting in FullList)
{
if(cleanList.Exists(x => x.ProcedureName == setting.ProcedureName))
setting.IsActive = true; // do you business logic here
else
setting.IsActive = false;
updateList.Add(setting);
}
You should be able to use something like this, it has worked okay for me:
var valuesToMatch = yourList.Where(stringCheck => stringCheck.Contains(myString));
or something like this, if you need to look where it doesn't match.
var valuesToMatch = yourList.Where(stringCheck => !stringCheck.Contains(myString));
you can use
var match=myList.Where(item=>item.Contains("Required String"));
foreach(var i in match)
{
//do something with the matched items
}
LINQ provides you with capabilities to "query" any collection of data. You can use syntax like a database query (select, where, etc) on a collection (here the collection (list) of strings).
so you are doing like "get me items from the list Where it satisfies a given condition"
inside the Where you are using a "lambda expression"
to tell briefly lambda expression is something like (input parameter => return value)
so for a parameter "item", it returns "item.Contains("required string")" . So it returns true if the item contains the string and thereby it gets selected from the list since it satisfied the condition.
To keep it simple use this;
foreach(string item in myList)//Iterate through each item.
{
if(item.Contains("Search Term")//True if the item contains search pattern.
{
return item;//Return the matched item.
}
}
Alternatively,to do this with for loop,use this;
for (int iterator = 0; iterator < myList.Count; iterator++)
{
if (myList[iterator].Contains("String Pattern"))
{
return myList[iterator];
}
}
It is possible to combine Any, Where, First and FirstOrDefault; or just place the predicate in any of those methods depending on what is needed.
You should probably avoid using First unless you want to have an exception thrown when no match is found. FirstOrDefault is usually the better option as long as you know it will return the type's default if no match is found (string's default is null, int is 0, bool is false, etc).
using System.Collections.Generic;
using System.Linq;
bool exists;
string firstMatch;
IEnumerable<string> matchingList;
var myList = new List<string>() { "foo", "bar", "foobar" };
exists = myList.Any(x => x.Contains("o"));
// exists => true
firstMatch = myList.FirstOrDefault(x => x.Contains("o"));
firstMatch = myList.First(x => x.Contains("o"));
// firstMatch => "foo"
firstMatch = myList.First(x => x.Contains("dark side"));
// throws exception because no element contains "dark side"
firstMatch = myList.FirstOrDefault(x => x.Contains("dark side"));
// firstMatch => null
matchingList = myList.Where(x => x.Contains("o"));
// matchingList => { "foo", "foobar" }
Test this code # https://rextester.com/TXDL57489
I have not seen bool option in other answers so I hope below code will help someone.
Just use Any()
string myString = "test";
bool exists = myList
.Where(w => w.COLUMN_TO_CHECK.Contains(myString)).Any();
You can check the list is empty or not in multiple ways.
1)Check list is null and then check count is greater than zero like below:-
if(myList!=null && myList.Count>0)
{
//List has more than one record.
}
2)Check list null and count greater than zero using linq query like below:-
if(myList!=null && myList.Count>0)
{
//List has more than one record.
}
I would like to know:
What technic is that code?
Can you rewrite that code to make it more readable, because I do
not completely understand its meaning.
Paragraph para = CaretPosition.Paragraph;
var matchedRun = para.Inlines.FirstOrDefault(inline =>
{
Run run = inline as Run;
return (run != null && run.Text.EndsWith(inputText));
}) as Run;
if (matchedRun != null)
{
}
I'd say a more readable version would be:
var matchedRun = para.Inlines
.OfType<Run>()
.FirstOrDefault(r => r.Text.EndsWith(intputText));
OfType filters the input sequence on the given type (Run) and FirstOrDefault finds the first Run instance whose Text property ends with the given input (or null if none was found).
It's Linq. Do you know the "var" keyword? It's a type that the compiler knows but the programmer doesn't want to write.
The re-written code without using Linq is
Paragraph para = CaretPosition.Paragraph;
Run matchedRun = null;
foreach (var inl in para.Inlines)
{
Run run = inl as Run;
if( (run != null) && run.Text.EndsWith(inputText))
{
matchedRun = run;
break;
}
}
if (matchedRun != null)
{
}
Note that I converted "inline" to "inl". It's not a keyword in C# but Stackoverflow makes it look like one.
Also note that it's even LESS readable once you get accustomed to Linq!
This code appears to be related to the RichTextBox class in the .NET Framework.
The CaretPosition.Paragraph.Inlines is a collection of "Inlines" that make up the body of the paragraph.
The code is basically looking for any Inlines that are of type Run, and setting the value of matchedRun to that first instance if there are any. The FirstOrDefault method is simply a convenient way to look inside a collection of objects and retrieve the first element or a default value if the collection is empty.
As far as readability, if you are familiar with LINQ syntax, it isn't too bad to wade through that code, though I do personally find the example code provided by Lee to be a bit more readable - mostly because of the use of another LINQ expression: OfType
it's called "THE MIGHTY LINQ TECHNIQUE" :)
Jokes apart
it is Linq method to get the First element from the collection or return default value.
var matchedRun = para.Inlines.FirstOrDefault(inline =>{ Run run = inline as Run; return (run != null && run.Text.EndsWith(inputText));}) as Run;
=> is called the Lambda techique for shorthand delagate decalaration
so you can read it as
Find 1st object from the para.Inlines collection where that object EndsWith some user suplied value or retrun default value if no match found
if you don't want to use this technique which actually reduces lot of code so you can try below equibvalent code
Paragraph para = CaretPosition.Paragraph;
var matchedRun = null;
foreach (var inl in para.Inlines)
{ Run run = inl as Run;
if ((run != null) && run.Text.EndsWith(inputText))
{ matchedRun = run; break; }
}
Now you can decide which is better to write
I have an extension method called ToListIfNotNullOrEmpty(), which is hitting the DB twice, instead of once. The first time it returns one result, the second time it returns all the correct results.
I'm pretty sure the first time it hits the database, is when the .Any() method is getting called.
here's the code.
public static IList<T> ToListIfNotNullOrEmpty<T>(this IEnumerable<T> value)
{
if (value.IsNullOrEmpty())
{
return null;
}
if (value is IList<T>)
{
return (value as IList<T>);
}
return new List<T>(value);
}
public static bool IsNullOrEmpty<T>(this IEnumerable<T> value)
{
if (value != null)
{
return !value.Any();
}
return true;
}
I'm hoping to refactor it so that, before the .Any() method is called, it actually enumerates through the entire list.
If i do the following, only one DB call is made, because the list is already enumerated.
var pewPew = (from x in whatever
select x)
.ToList() // This enumerates.
.ToListIsNotNullOrEmpty(); // This checks the enumerated result.
I sorta don't really want to call ToList() then my extension method.
Any ideas, folks?
I confess that I see little point in this method. Surely if you simply do a ToList(), a check to see if the list is empty suffices as well. It's arguably harder to handle the null result when you expect a list because then you always have to check for null before you iterate over it.
I think that:
var query = (from ...).ToList();
if (query.Count == 0) {
...
}
works as well and is less burdensome than
var query = (from ...).ToListIfNotNullOrEmpty();
if (query == null) {
...
}
and you don't have to implement (and maintain) any code.
How about something like this?
public static IList<T> ToListIfNotNullOrEmpty<T>(this IEnumerable<T> value)
{
if (value == null)
return null;
var list = value.ToList();
return (list.Count > 0) ? list : null;
}
To actually answer your question:
This method hits the database twice because the extension methods provided by the System.Linq.Enumerable class exhibit what is called deferred execution. Essentially, this is to eliminate the need for constructing a string of temporarily cached collections for every part of a query. To understand this, consider the following example:
var firstMaleTom = people
.Where(p => p.Gender = Gender.Male)
.Where(p => p.FirstName == "Tom")
.FirstOrDefault();
Without deferred execution, the above code might require that the entire collection people be enumerated over, populating a temporary buffer array with all the individuals whose Gender is Male. Then it would need to be enumerated over again, populating another buffer array with all of the individuals from the first buffer whose first name is Tom. After all that work, the last part would return the first item from the resulting array.
That's a lot of pointless work. The idea with deferred execution is that the above code really just sets up the firstMaleTom variable with the information it needs to return what's being requested with the minimal amount of work.
Now, there's a flip side to this: in the case of querying a database, deferred execution means that the database gets queried when the return value is evaluated. So, in your IsNullOrEmpty method, when you call Any, the value parameter is actually being evaluated right then and there -- hence a database query. After this, in your ToListIfNotNullOrEmpty method, the line return new List<T>(value) also evaluates the value parameter -- because it's enumerating over the values and adding them to the newly created List<T>.
You could stick the .ToList() call inside the extension, the effect is slightly different, but does this still work in the cases you have?
public static IList<T> ToListIfNotNullOrEmpty<T>(this IEnumerable<T> value)
{
if(value == null)
{
return null;
}
var result = value.ToList();
return result.IsNullOrEmpty() ? null : result;
}