How to use if statement within IMongoCollection.Find() method? - c#

I have two different filter options for the Find() method depending on the value of the parameter. So I want to combine them in one lambda function.
It is easy to write separate methods for each options:
if (status == null)
{
var dbOrders = orderCollection
.Find(t => true)
.ToList();
}
else
{
var dbOrders = orderCollection
.Find(t => t.Status==status)
.ToList();
}
Obviously, it is not the best way to do. I think it can be done within one lambda function.
I have tried something like that, but it seems that it is not correct
var dbOrders = orderCollection
.Find(t => status == null: true ? t.Status==status)
.ToList();
What is the correct way to achieve it?

Related

Using LINQ to populate a string with a single column value

I'm a newbie both to C# and to LINQ and would appreciate a small push in the right direction.
Firstly, I have an Overrides SQL table (and a corresponding EF DB context), which has a Type, Value, and Override Value. The idea is that for a particular kind ("Type") of override, the code can check a particular value and go see if there is an override value that should be used instead.
var branchOverrides = overridesSqlContext.Overrides
.Where(q => q.Type == "Branch Override")
.Select(s => new
{
s.Value,
s.OverrideValue
});
In this case, I want the list of different override values of the "Branch Override" type. From there, I would like to be able to retrieve a specific override value at a given point within my code. How can I query the branchOverrides variable I've created to be able to say something like:
string readingOverride = select OverrideValue from branchOverrides where Value = "Reading"
My code will need to be able to read various override values for different branches at different points, and being able to query the branchOverrides variable at any point would seem like the ideal approach.
Thank you for any assistance on this.
You can use Single() on the query object you have:
string readingOverride = branchOverrides
.Single(bo => bo.Value == "Reading")
.OverrideValue;
This will throw an exception if an entry doesn't exist though so you probably want to use SingleOrDefault instead and check for a null return.
Also note that the branchOverrides object here is an IQueryable<> which means that every time you use it, it will send a query to the database. You may want to materialise that to a local list by adding .ToList() after the Select(...). Alternatively, you may want to look at caching this data, especially if it's going to be used frequently.
If I understood you right, you want the entry with Value = "Reading" and Type="Branch Override":
var branchOverride = overridesSqlContext.Overrides
.SingleOrdDefault(q => q.Type == "Branch Override"
&& q.Value == "Reading")
.Select(s => new
{
s.Value,
s.OverrideValue
});
if (branchOverride != null)
{
// do whatever ...
}
For performance issue is good to put .ToList() in the end of your LINQ expression if you need to iterante over that list too many times.
var branchOverrides = overridesSqlContext.Overrides
.Where(q => q.Type == "Branch Override")
.Select(s => new
{
s.Value,
s.OverrideValue
}).ToList();
If it you will load the entire list into the memory avoiding to execute the sql query to fetch the data if you need to iterate through your list.
Other thing that you can do is:
string readingOverride = string.Empty;
var branchOverride = branchOverrides.FirstOrDefault(x => x.Value == "Reading");
if(branchOverride != null)
{
readingOverride = branchOverride.OverrideValue;
}
Hope that helps.
If Value is unique within "Branch Override" perhaps you want to turn it to a dictionary for fast lookup
var branchOverrides = overridesSqlContext.Overrides
.Where(q => q.Type == "Branch Override")
.Select(s => new
{
s.Value,
s.OverrideValue
})
.ToDictionary(k => k.Value, v => v.OverrideValue);
Then later on you can find the override value quickly and efficiently
var readingOverride = branchOverrides["Reading"];

Mock method return based on object parameter

I have the following (simplified) code:
public string methodName(ClassType object)
{
If(object.value == 1)
return "Yes";
else If(object.value == 2)
return "No";
else
return "whatever";
}
I am then calling this method in a unit test, and need to mock the return type based on the object value:
_Service.Setup(x => x.methodName(new methodName { value = 1}).Returns("Yes");
_Service.Setup(x => x.methodName(new methodName { value = 2}).Returns("No");
I know what I have written is wrong - but how can I achieve this?
You're on the right track. With Moq, you need to specify exactly which setup should match each input. You do it like this:
_Service.Setup(x => x.methodName(It.IsAny<ClassType>())).Returns("whatever");
_Service.Setup(x => x.methodName(It.Is<ClassType>(o => o.value == 1))).Returns("Yes");
_Service.Setup(x => x.methodName(It.Is<ClassType>(o => o.value == 2))).Returns("No");
The first line there sets up the mock to return "whatever" whenever this method is called with any value. The following two lines override that behavior for specific values.
I'd check out Moq's Quickstart guide for more details, and the Matching Arguments section in particular.
I´m not that familiar with Moq, however I asume the following should do it. You should provide a single Returns for every possible value for your parameter:
_Service.Setup(x => x.methodName(It.Is<ClassType>(y => y.value == 1))).Returns("Yes");
_Service.Setup(x => x.methodName(It.Is<ClassType>(y => y.value == 2))).Returns("No");
This way whenever your methodName-method is called with object.value == 1, "Yes" is returned, while object.value == 2 resolves to the method returning "No".
However to me this makes not much sense as you´re mocking the behaviour of methodName with the exact same behaviour. I suppose this is just for research.

use "Like" Expression, LINQ to Entity

I spent long time trying to fix this but I'm not getting anywhere, so i help someone helps me.
I have a search form where I wish to use the Like % operator in the textbox.
Here is a snippet of my code:
var data = mg.DatabaseTable.Where(m => m.UserName.StartsWith(TextBoxUserID.Text) &&
m.Content.Like(%TextBoxBarcode.Text&) &&
m.Action.StartsWith(DropDownListStatus.Text) &&
m.Site.Contains(TextBoxSite.Text));
I would like it to be possible to use "%%" in the m.Content(textbox) or however it's made.
I am aware the use of StartsWith, EndWith and Contains. I would like to make it possible to choose how to query the search by using "like %"
You can use:
m.Content.StartsWith(TextBoxBarcode.Text);
for
like 'search%'
or:
m.Content.EndsWith(TextBoxBarcode.Text);
for
like '%search'
or:
m.Content.Contains(TextBoxBarcode.Text);
for
like '%search%'
If you want the user to be able to choose the type of search then you'll need to have a switch and then three different queries. Either replicate the query or perform the basic query once and then filter the results of that depending on the switch:
var data = mg.DatabaseTable.Where(m => m.UserName.StartsWith(TextBoxUserID.Text) &&
m.Action.StartsWith(DropDownListStatus.Text) &&
m.Site.Contains(TextBoxSite.Text));
if (searchMode == StartsWith)
{
return data.Where(m => m.Content.StartsWith(TextBoxBarcode.Text);
}
else if (searchMode == EndsWith)
{
return data.Where(m => m.Content.EndsWith(TextBoxBarcode.Text);
}
else
{
return data.Where(m => m.Content.Contains(TextBoxBarcode.Text);
}

How to use System.Linq.Expressions.Expression to filter based on children?

I have a filter that I use across many methods:
Expression<Func<Child, bool>> filter = child => child.Status == 1;
(actually is more complex than that)
And I have to do the following
return db.Parents.Where(parent => parent.Status == 1 &&
parent.Child.Status == 1);
where the condition is the same as in the filter above.
I want to reuse the filter in this method. But I don't know how. I tried
return db.Parents.Where(parent => parent.Status == 1 &&
filter(parent.Child));
but an Expression can't be used as a method
If you want to combine expressions and still be able to use linq-to-sql, you may want to have a look at LinqKit. It walks inside your expression and replaces all the function calls by their contents before the sql conversion.
This way you'll be able to use directly
return db.Parents
.AsExpandable()
.Where(parent => parent.Status == 1 && filter(parent.Child));
You can try this:
var compiledFilter = filter.Compile();
foreach (var parent in db.Parents.Where(parent => parent.Status == 1))
if (compiledFilter(parent.Child))
yield return parent;
It requires you to pull all of the parents, but unlike #HugoRune's solution, it doesn't require a 1:1 relation of Parent:Child.
I don't think this will be useful for your situation because of the different types involved, but just in case, here is an example of how you can combine Expressions: How do I combine LINQ expressions into one?
Edit: I had previously suggested using Compile(), but that doesn't work over LINQ-to-SQL.
Well, if there is a 1:1 relationship between parent and child
(unlikely, but the example seems to imply that) then you could do it like this:
return db.Parents
.Where(parent => parent.Status == 1)
.Select(parent => parent.Child)
.Where(filter)
.Select(child=> child.Parent);
Otherwise it will be hard.
You could do it with dynamic linq but that is probably overkill.
You could generate your expression tree manually, but that is also quite complicated. I have not tried that myself.
As a last resort you could of course always call yourQuery.AsEnumerable(), this will cause linq-to-sql to translate your query into sql up to this point and perform the rest of the work on the client-side; then you can .compile() your expression. However you lose the performance benefits of linq-to-sql (and compile() itself is quite slow; whenever it is executed, it calls the JIT-compiler):
return db.Parents
.Where(parent => parent.Status == 1)
.AsEnumerable()
.Where(parent => filter.Compile().Invoke(parent.Child))
Personally I'd just define the expression twice, once for child and once for parent.child:
Expression<Func<Child, bool>> filterChild = child => child.Status == 1;
Expression<Func<Parent, bool>> filterParent = parent => parent.Child.Status == 1;
Might not be the most elegant, but probably easier to maintain than the other solutions
Just come up with this, check if this would work for you
public interface IStatus { public int Status { get; set; } }
public class Child : IStatus { }
public class Parent : IStatus
{public Child Child { get; set; } }
Func<IStatus, bool> filter = (x) => x.Status == 1;
var list = Parents.Where(parent => filter(parent) && filter(parent.Child));
Hope this helps!
Could you just use the expression as a function instead?
Instead of:
Expression<Func<Child, bool>> filter = child => child.Status == 1;
Use that same expression as a generic function this way:
Func<Child, bool> filter = child => child.Status == 1;
Then you will be able to use the function in just the same way you were trying to use an expression:
return db.Parents.Where(parent => parent.Status == 1 &&
filter(parent.Child));
Edit: I misunderstood the question. This is a bad answer. 6+ years out, I'm still getting comments to the effect that this doesn't work. I'm not sure, from a hygiene perspective, if it would be better to just delete the answer, or add this edit and let the answer stand as an example of something that decidedly doesn't work. I'm open to advisement on that.
There's no need for external libraries or mucking around with expression trees. Instead, write your lambda functions to use query chaining and take advantage of LINQ's deferred execution.
Instead of:
Expression<Func<Child, bool>> filter = child => child.Status == 1;
Rewrite it as:
Func<IQueryable<Parent>, IQueryable<Parent>> applyFilterOnParent = query => query.Where(parent => parent.Child.Status == 1);
Func<IQueryable<Child>, IQueryable<Child>> applyFilterOnChild = query => query.Where(child => child.Status == 1);
Now, instead of:
return db.Parents.Where(parent => parent.Status == 1 &&
filter(parent.Child));
You can write:
var query = db.Parents.AsQueryable();
query = applyFilterOnParent(query);
return query.Where(parent => parent.Status == 1);
And you can re-use the applyFilter functions in other LINQ queries. This technique works well when you want to use lambda functions together with LINQ-to-SQL, because LINQ will not translate a lambda function to SQL.

how to select an item from generic list by linq

I have a LINQ query which contains a method GetInstanceForDatabase()
principlesList.Select(p => p.GetInstanceForDatabase()).ToList()
where
List<PrincipleInstance>() principlesList = ...
// (contains list of principle like "Manual Trades", "OPM", "Flora")
GetInstanceForDatabase() is a method which takes all other info about a principle (like manual trades).
My problem is that I want to sort out only principle like only "Manual Trades".
I want to put a where clause. I tried but it is fails.
To get a single item use:
query.First(x => x.property == "Manual Trades");
// or
query.FirstOrDefault(x => x.property == "Manual Trades");
var list = p.GetInstanceForDatabase().where(x => x.propertyName == "Manual Trades").ToList();
I'm sure you're GetInstanceForDatabase needs to return your collection that you then filter for the 'Manual Trades' but I can't really tell how you get your list of PrincipalInstances from the question.
This is the correct syntax of using Where in LINQ
principlesList.Select(p => p.GetInstanceForDatabase()).Where(p => p.SomeProperty == "SomeValue").ToList();

Categories