Formatting LINQ Query Result Set - c#

I am working on an ASP.NET MVC application. This application executes a query via JQuery. The result set is returned as JSON from my ASP.NET MVC controller. Before I return the serialized result set, i need to trim it down to only the properties I need. To do this, I'm using a LINQ Query. That LINQ Query looks like the following:
private IEnumerable RefineResults(ResultList<Result> results)
{
// results has three properties: Summary, QueryDuration, and List
var refined = results.Select(x => new
{
x.ID, x.FirstName, x.LastName
});
return refined;
}
When I execute this method, I've noticed that refined does not include the Summary and Duration properties from my original query. I'm want my result set to be structured like:
Summary
QueryDuration
Results
- Result 1
- Result 2
- Result 3
...
At this time, when I execute RefineResults, I get the result list I would expect. However, I can't figure out how to put those entries in a property called "Results". I also don't know how to add the "Summary" and "QueryDuration" properties.
Can someone please point me in the right direction?
Thanks!

private object RefineResults(ResultList<Result> results)
{
// results has three properties: Summary, QueryDuration, and List
var refined = results.Select(x => new
{
x.ID, x.FirstName, x.LastName
});
return new { Results = refined, Summary = results.Summary, QueryDuration = results.QueryDuration };
}
You will probably want to create a specific DTO class for the return value of this function.

Related

In C# Groupby Select using a ForEach or other function to aggregate one column into a array of results

I have a groupby function that is creating a series of columns in a select. For one one the columns I want to return a array of results of a field saved under that column header, but I can't seem to figure out how to write this queries in linq.
Example code
var res = students.GroupBy(x => x.ClassId).Select(a => new {
ClassHours = a.Sum(r => r.Hours),
AvgAttendance = a.Average(r => r.AttendanceRate),
NumStudents = a.Count(),
// I want to get a list of all student names but not sure how to do this,
I want a array return of student names, I tried with for each but this doesn't seem to work but I'm not sure what to do
StudentNames = a.ForEach(r => return r.StudentName)
// I want to do something like this but make the rest a array e.g. StudentNames = ["Blaise", "Sasha", "Jeff"]
});
Hard to be certain without knowing what your object looks like, but presumably you can you just use Select?
StudentNames = a.Select(r => r.StudentName).ToArray()

Mongo C# filter on integer contains

I've a collection with orders, each with an OrderId field of type int32. I would like to filter the collecting and get all orders where the OrderId contains e.g. 123. For instance the following OrderIds must match:
123
9912399
99123
The following raw mongo filter works:
{ $where: "/^.*123.*/.test(this.OrderId)" }
How can this be expressed in the C# Mongo client or something different that does the job?
I'm not able to use the below code, as it seems to only work in string fields:
Builders<Order>.Filter.Regex(x => x.OrderId, new BsonRegularExpression("123"))
ideally you should store a string version of the order id in your documents. in case that's not an option you can do the following aggregation pipeline:
var res = await collection
.Aggregate()
.AppendStage<object>("{ $set : { orderIdString : { $toString : '$OrderId' } } }")
.Match(Builders<object>.Filter.Regex("orderIdString", "/123/"))
.AppendStage<object>("{ $unset : 'orderIdString' }")
.As<Order>()
.ToListAsync();
I don't think you can generate $where via typed builders. So, as it was mentioned above, the only option you have is to create a filter from a raw MQL like below:
var coll = db.GetCollection<Order>("coll");
var result = coll.Find("{ $where: '/^.*123.*/.test(this.OrderId)' }").ToList();
Did you try using:
x => x.OrderId.ToString()
instead of
x => x.Orderid
You can use Filter.Regex to achieve the desired behavior:
var valueToFilterBy = "123"
var filter = Builders<Order>.Filter.Regex(nameof(Order.Id), new BsonRegularExpression($".*{valueToFilterBy}.*"));
var data = await collection.FindAsync(filter).ToListAsync();

How to use multi-valued/array parameter(enum values) obtained from Request.Query in LINQ queries?

I'm still new to modern styles .NET development and Entity Framework. I'm trying to get a list of objects where one of the values falls in a list of other values, and I'm trying to use the LINQ query methods to do so.
string cb_orderstatus = Request.Query["OrderStatusSearch"].ToString();
if (!string.IsNullOrEmpty(cb_orderstatus))
{
string[] orderStatuses = cb_orderstatus.Split(",");
query = query.Where(o => orderStatuses.Contains(o.Status.ToString()));
}
If the value of the cb_orderstatus is a string array containing 5, 10, and 15, I want the query to return objects where their Status equals any of these values. Currently it is not working. Can anyone help?
It is an educated guess, but as you say that
o.Status is an OrderStatus enum
then most probably you need to convert values from cb_orderstatus to actual OrderStatuses values and use OrderStatus[].Contains in the query
string cb_orderstatus = Request.Query["OrderStatusSearch"].ToString();
if (!string.IsNullOrEmpty(cb_orderstatus))
{
var orderStatuses = cb_orderstatus
.Split(",")
.Select(statusIntegerString =>
(OrderStatus)int.Parse(statusIntegerString))
.ToArray();
query = query.Where(o => orderStatuses.Contains(o.Status));
}
Though I am not sure that you will get comma-separated values from Request.Query["OrderStatusSearch"].
In any case, it would be orders of magnitude better to rely on standard parameter binding, so I'd recommend you to post another question that deals with
I have a property on the model class that has [BindProperty] on it and is of type List but it is not being populated with any data.

Linq query returns unwanted results as well

I'm new to linq and C#, trying to query complex objects by a certain property. The scenario is I have a list of currentPerson objects, which include PersonAddressesDisplay property, which is a string. I'm looping over the list of trying to find saved person objects in the DB by their address (PersonAddressesDisplay). Right now for some odd reason I get unwanted results as well (different strings also get in the matchAddresses list). The query is as follows:
foreach(var currentPerson in PersonsListToSave) {
.
.
.
var matchAddresses = db.PersonAddresses.Include(p => p.Persons).AsEnumerable().
Where(add => currentPerson.Addresses
.Any(personAddress => personAddress.PersonAddressesDisplay == add.PersonAddressesDisplay)).ToList();
// matchAddresses includes unwanted results
.
.
.
}
If you want to extract PersonAddress+Person objects which share at least address with the currentPerson, then you can construct a query for that purpose directly:
foreach(var currentPerson in PersonsListToSave)
{
// ...
IEnumerable<string> currentAddresses =
currentPerson.Addresses.Select(personAddr => personAddr.PersonAddressesDisplay);
var matchAddresses = db.PersonAddresses.Include(p => p.Persons)
.Where(addr => currentAddresses.Contains(addr.PersonAddressesDisplay))
.ToList();
// ...
}
I cannot try this code, but I think that it should work correctly by constructing the WHERE - IN SQL filter under the hood. Please try it out and send more info if this is not solving the issue.

How to filter a List<T> if it contains specific class data?

I need help with filtering list data in c#.
I got 3 class named Product.cs, Storage.cs and Inventory.cs.
public class Storage{
string StorageId;
string Name;
}
public class Inventory{
string InventoryId;
string StorageId;
string ProductId;
}
I got the filled List<Storage> mStorages, List<Product> mProduct and List<Inventory> mInventories.
I have trouble to print mStorages that contain with specific productId that only can be obtained from mInventories.
So, I tried this:
List<Storage> mFilteredStorage;
for(int i=0;i<mStorages.Count;i++){
if(mStorages[i] contain (productId from inventories)){
mFilteredStorage.add(mstorages[i]);
}
So I can get mFilteredStorage that contains specific product from inventories. (in inventories there are lot of product id).
What should I do to get that filteredStorage? I tried to use list.contains() but it only return true and at last there are duplicated storage at mFilteredStorage.
Really need your help guys. Thanks in advance.
I suggest you to read about lambda-expressions, that is what you are looking for.
mFilteredStorage.AddRange(mStorages.Where(storage => inventories.Any(inventory => inventory.productId == storage.productId)).ToList());
This returns you a list with your filtered conditions. So right after Where you iterate over each item in your list, I called this item storage. (you can name those what ever you want to) Then we iterate over your object inventories with another lambda expression. This, the second lambda expression, returns either true if any of inventories's productIds match the productId of the current iterating object of mStorages or false if they don't match.
So you once the productIds match you can imagine the code like the following:
mStorages.Where(storage => true);
And once the result of the second lambda expression is true, storage will be added to the IEnumerable you will get as a result of the Where method.
Since we get an IEnumerable as return, but we want to add those Storage objects to mFilteredStorage, I convert the IEnumerable to a list, by:
/*(the return object we get from the `Where` method)*/.ToList();
You can use LINQ to accomplish your goal. Since Storage has no ProductId, the query will match by StorageId.
var filteredStoragesQry =
from storage in mStorages
where inventories.Any(inventory => inventory.StorageId == storage.StorageId)
select storage;
mFilteredStorages = filteredStoragesQry.ToList();
This query is for LINQ to objects, but it will also work in Entity Framework, when you replace mStorages and inventories by the respective DbSet objects from the context.
mStorages.Join(mInventories, x => x.StorageId, y => y.StorageId, (x, y) => new { Storage = x, ProductId = y.ProductId})
.Where(z => z.ProductId == "specificProductId").Select(z => z.Storage).ToList()
I ended with this code.
mFilteredStorage = tempStorage.GroupBy(s => s.Id).Select(group => group.First()).ToList()
This code is what I want to show.

Categories

Resources