Linq query to get value from nested object - c#

I need to pull a specific value from a nested object without using a foreach loop. I think the right approach here is a linq query, but I'm unable to grab the value I need. Considering the class structure:
public class Order
{
public int OrderID { get; set; }
public List<OrderItems> { get; set; }
}
public class OrderItems
{
public int OrderItemID { get; set; }
public string ItemName { get; set; }
public int Quantity { get; set; }
public List<OrderItemShipping> OrderItemShippings { get; set; }
}
public class OrderItemShipping
{
public int OrderItemShippingID { get; set; }
public Address ShipAddress { get; set; }
public class Address
{
public int AddressID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
}
I want to be able to do something like:
var shipToAddress = Order.OrderItems.OrderItemShipping.FirstOrDefault(x => x.Address.Address1);
But my syntax must not be correct, because I'm unable to grab the value I need?

If you need to access items of (nested) collections SelectMany is your friend:
var shipToAddress = Order.OrderItems
.SelectMany(oi => oi.OrderItemShipping.Select(ois => ois.ShipAddress.Address1)))
.FirstOrDefault();
Your syntax was wrong because the overload of FirstOrDefault expects a predicate(so a function that returns a bool) but you were passing: FirstOrDefault(x => x.Address.Address1).
If you need to filter it somehow("specific value from a nested object") you need to explain your requirement more precisely.

Related

How to use .Select to achieve .ThenInclude?

I want to Read Related Data but only read the specific field.
if use include theninclude will read all fiedl.
so I use .Select, but how to use .Select to achieve .ThenInclude?
Thanks~
var ViewModel = await _context.A_Table
.Select(s => new ViewModel {
A_TableId = s.Id,
B_Table = s.B_Table,
C_Table = ??? (s.B_Table.C_Table is wrong)
});
public class A_Table
{
public int Id { get; set; }
public string Field1 { get; set; }
public IList<B_Table> B_Table { get; set; }
}
public class B_Table
{
public int Id { get; set; }
public string Field1 { get; set; }
public int A_TableId { get; set; }
public int C_TableId { get; set; }
public C_Table C_Table { get; set; }
}
public class C_Table
{
public int Id { get; set; }
public string Field1 { get; set; }
public B_Table B_Table { get; set; }
}
this is because B_Table property is list of B_Table so when you want to access C_Table property inside it you have to specify which item in the list you want to access
e.g. s.B_Table[0].C_Table to access first item in the list.
if you want aggregate all items in side the list you can use SelectMany using Linq inside namespace System.Linq
e.g. s.B_Table.SelectMany(B_Table => B_Table.C_Table).ToList()

nPoco - Get single object with nested data

I have two Dto's:
[TableName("Address")]
public class AddressDto
{
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string Street { get; set; }
public string Building { get; set; }
public string Appartment { get; set; }
public string ZipCode { get; set; }
public string Floor { get; set; }
public DateTime CreatedDate { get; set; }
}
[TableName("DistributionPoint")]
public class DistributionPointDto
{
[Column("Id")]
public int Id { get; set; }
public string Name { get; set; }
[Reference(ReferenceType.Foreign, ColumnName = "AddressId", ReferenceMemberName = "Id")]
public AddressDto Address { get; set; }
}
How can I get DistributionPointDto with nested AddressDto using nPoco?
I have a generic repository for CRUD with method:
public T FindById<T>(int id)
{
return _db.SingleById<T>(id);
}
But, when I'm trying to get DistributionPointDto, AddressDto is null
Curious if you got your code to work, but I have found that you need to use Query instead of SingleById to include referenced properties, and then you can use an Include statement/clause, however I don't think generics work with this, you have to explicitly mention the referenced property name, which is AddressDTO for you.
_db.Query<DistributionPointDTO>()
.Include(x => x.AddressDTO)
.Where(x => x.Id == id).First();

removing certain objects from list of objects in c#

i have a list of objects
public int id { get; set; }
public string device_code { get; set; }
public string device_type { get; set; }
public string authentication_token { get; set; }
public string Status { get; set; }
while returning the list i want to remove "device_code" and "device_type" from the list and return the list only with "id","authentication_token" and "status".
How can I delete certain objects?
You must cast your object to another type that will contain only needed properties.
You can do this easy with linq:
var result = yourCollection.Select(x => new YourTempClass(){property1=x.property1});
You seem to not want to remove objects, but properties of the objects.
public class ClassWithAllProperties
{
public int id { get; set; }
public string device_code { get; set; }
public string device_type { get; set; }
public string authentication_token { get; set; }
public string Status { get; set; }
}
var allInstances = new List<ClassWithAllProperties>();
// populate list
var allInstancesButNotAllProperties = allInstances.Select(x => new { id = x.id, authentication_token = x.authentication_token, Status = x.Status }).ToList();
Now this list contains only the properties you want. However it obviously also does not contain instances of ClassWithAllProperties. It contains so-called anonymous classes. Classes the compiler builds in the background for you, based on your description in the new.
It's simple, create another class containing properties that are required and then return its object using the list you have created.
Original Class
public class Data {
public int id { get; set; }
public string device_code { get; set; }
public string device_type { get; set; }
public string authentication_token { get; set; }
public string Status { get; set; }
}
Class That will be returned
public class DataTobeReturned {
public int id { get; set; }
public string authentication_token { get; set; }
public string Status { get; set; }
}
Suppose you have list like
List<Data> list = // some data;
You can do
List<DataTobeReturned> list2 = list.Select(x => new DataTobeReturned { x.id, x.Status, x.authentication_token}).ToList();
Simply return the list2 object.
If you have this class:
class MyClass
{
public int id { get; set; }
public string device_code { get; set; }
public string device_type { get; set; }
public string authentication_token { get; set; }
public string Status { get; set; }
}
...and you have a list of them...
List<MyClass> list;
You can extract just the properties you want into an anonymous type by using LINQ:
var justWhatIWant = list.Select( a => new
{
id = a.id,
authentication_token = a.authentication_token,
Status = a.Status
});
The anonymous type isn't interface-compatible with anything, but you could use it to, say, create some JSON.

Entity Framework Query based on child object filter and at the same time on the main object

I have a class called Query with a field called CreatedBy, the username who created it.
I also have a class called Permissions with the permissions for the query.
I created a query that returns me based on the current user, the queries the user has access to, based on the Permissions collection, but I need to JOIN that with the queries that the user also created.
If for some reason, the user who created it, its also in the Permissions collection, it shouldnt be returned twice.
Here is my code
public class Query
{
public int QueryId { get; set; }
public string QueryName { get; set; }
public string QuerySql { get; set; }
public string CreatedBy { get; set; }
public string QueryType { get; set; }
public string RequestType { get; set; }
public string Column1 { get; set; }
public string Operator1 { get; set; }
public string Value1 { get; set; }
public string Connector2 { get; set; }
public string Column2 { get; set; }
public string Operator2 { get; set; }
public string Value2 { get; set; }
public string Connector3 { get; set; }
public string Column3 { get; set; }
public string Operator3 { get; set; }
public string Value3 { get; set; }
public virtual ICollection<Permission> Permissions { get; set; }
}
public class Permission
{
public int PermissionId { get; set; }
public string UserName { get; set; }
}
public IQueryable<Query> GetQueriesForUser(string userName)
{
return _context.Queries.Where(q => q.Permissions.Any(p => p.UserName.Equals(userName)));
}
Are you sure you need a join? It looks like you need UNION ALL:
_context.Queries.Where(q => q.Permissions.Any(p => p.UserName == userName)).Concat(
_context.Queries.Where(q => q.CreatedBy == userName));

Strongly Typed List.GroupBy()

I've been trying to find an answer to this on google and on SO
but everywhere I have found uses anonymously typed result lists
what I am trying to acheive is to take a List<SecondaryStandard>
and create a grouped List of SecondaryStandard
each SecondaryStandard looks like this
public class SecondaryStandard
{
public string Id { get; set; }
public int IdNumeric { get; set; }
public string IdText { get; set; }
public Sample Sample { get; set; }
public string StandardName { get; set; }
public DateTime DateCompleted { get; set; }
public SamplePoint SamplingPoint{ get; set; }
public Instrument Instrument{ get; set; }
public string ContainerId { get; set; }
public double Value { get; set; }
public string ComponentName { get; set; }
public string PointLocation { get; set; }
public string Description { get; set; }
public string Description2 { get; set; }
public string Analysis { get; set; }
public string Units { get; set; }
}
what i want is a List() where the Value Property is an average of results for each ComponentName.
Any ideas on how I could achieve this in a strongly typed way or do I need to suck it up and use anonymous objects to achieve what I'm looking for?
You mean this?
List<SecondaryStandard> list = new List<SecondaryStandard>();
// populate list
List<SecondaryStandard> result = list
.GroupBy(l => l.ComponentName)
.Select(s => new SecondaryStandard() { ComponentName = s.Key, Value = s.Average(x => x.Value) }).ToList();

Categories