I unable to come up with a linq query for the following scenario.
public class Product
{
public virtual string ProductName { get; set; }
public virtual IList<SubProduct> SubProducts { get; set; }
}
public class SubProduct
{
public string SubProductName { get; set; }
public int SubProductTypeId { get; set; }
}
public class SubProductType
{
public int SubProductTypeId{ get; set; }
public string Description { get; set; }
}
var productList = List<Product>();
var subProductTypeLlist = List<SubProductType>();
I have a list of products and each product has list of SubProducts. I want to get the query to represent {ProductName, Description}. Please suggest how to write linq query.
Something like this should do the trick:
var result = productList
.SelectMany(p => p.SubProducts
.Select(sp => new { SubProduct = sp, ProductName = p.ProductName }))
.Select(sp =>
new { Description = subProductTypeList
.Single(spt => spt.SubProduct.SubProductTypeId == sp.SubProductTypeId).Description,
ProductName = sp.ProductName })
In the SelectMany, we first do a Select on the internal IEnumerable (IList implements IEnumerable) to convert each SubProduct object to an anonymous class holding the SubProduct object and the ProductName. The SelectMany then converts that to a flat list. We then use Select on that list to create a new anonymous class again, where this time, we grab the Description from subProductTypeList. The result is an IEnumerable of an anonymous class with the members Description and ProductName.
Related
Not sure if i worded the question correctly, but what im trying to do is return a new viewmodel with one of the parts being a booking:
public class Booking
{
public int BookingId { get; set; }
public int CustomerId { get; set; }
public Guid UniqueId { get; set; }
public string EventId { get; set; }
public bool IsPaid { get; set; }
public double Price { get; set; }
public DateTime BookingDate { get; set; }
public DateTime DateBooked { get; set; }
[JsonIgnore]
public Customer Customer { get; set; }
[JsonIgnore]
public ICollection<BookingService> BookingServices { get; set; }
[NotMapped]
public IEnumerable<Service> Services { get; set; }
}
and my query is:
var customers = _dbContext.Customers
.Select(c => new CustomerBookingsViewModel
{
Customer = c,
Bookings = c.Bookings.Select(b => new Booking
{
BookingId = b.BookingId,
BookingDate = b.BookingDate,
DateBooked = b.DateBooked,
CustomerId = b.CustomerId,
UniqueId = b.UniqueId,
EventId = b.EventId,
IsPaid = b.IsPaid,
Price = b.Price,
Services = b.BookingServices.Select(s => s.Service)
}),
}
)
.ToList();
What I want to know is how to I select all the booking info into the booking without selecting each part, ie:
BookingId = b.BookingId,
BookingDate = b.BookingDate,
DateBooked = b.DateBooked,
CustomerId = b.CustomerId,
UniqueId = b.UniqueId,
EventId = b.EventId,
IsPaid = b.IsPaid,
Price = b.Price,
Can it be done or because the list of services is inside the booking model it cant?
Thanks.
You could implement the IClonable interface on your class.
public class MyClass : ICloneable
{
public int Id { get; set; }
public object Clone() => MemberwiseClone();
}
Usage:
var list1 = new List<MyClass>
{
new MyClass() { Id = 2 },
new MyClass() { Id = 5 }
};
var list2 = list1.Select(x => (MyClass)x.Clone()).ToList();
list2.First().Id = 10; //list1 won't be affected
You should use AutoMapper here to avoid writing each path.
https://automapper.org/
http://docs.automapper.org/en/stable/Getting-started.html
There is no other way, at least it is not related to LINQ or queries.
The question "How to clone an object" has been answered here:
Creating a copy of an object in C#
There is no LINQ way to do this. I would suggest using custom Attribute marking every property you want to copy. This would help if you want not to copy the whole object but some properties. After marking every property you need you can just set the marked props with reflection from one of the objects to the other.
I have the following database entity containing ingredients to put on pizza. Column Type is a foreign key to another table containing information on the ingredient category (cheese, meat, vegetables etc.)
public class Ingredient
{
public int IngredientId { get; set; }
public string Name { get; set; }
public bool IsVegetarian { get; set; }
public int Type { get; set; }
}
Some sample data:
sample ingredients
For each unique 'Type' value, I want to return a List of Ingredients with that type.
The final result will be stored in an ICollection of type IngredientViewModel.
public class IngredientViewModel : Model
{
public IngredientCategory Category { get; set; }
public List<Ingredient> Ingredients { get; set; }
}
How can I best get all ingredients, grouped per category in a single database trip using linq or lambda expressions?
I currently have the following snippet which I find a bit messy:
public async Task<IEnumerable<IngredientViewModel>> GetIngredientsPerCategoryAsync()
{
IEnumerable<Ingredient> result = await _repo.GetAllAsync();
IEnumerable<IngredientViewModel> viewModels = result.GroupBy(
x => x.Type,
(category, ingredients) => new IngredientViewModel()
{
Category = (IngredientCategory)category,
Ingredients = MapFromEntities(ingredients)
})
.OrderBy(x => x.Category.ToString())
.ToList();
return viewModels;
}
The most obvious would be: Ingredients = g.ToList().
Following scenario:
public class User{
public virtual ICollection<MediaItem> MediaItems { get; set; }
}
public enum eMediaItemGenre
{
[Display(Name = "Pop")]
POP = 0,
[Display(Name = "Other")]
OTHER = 11
}
public class MediaItem
{
public virtual ICollection<MediaItemGenre> Genres { get; set; }
}
public class MediaItemGenre
{
[Key]
public Int32 Id { get; set; }
public eMediaItemGenre Genre { get; set; }
public Int32 MediaItemId { get; set; }
public virtual MediaItem MediaItem { get; set; }
}
Now I would like to do the following: I have a MediaItem and I would like to find MediaItems that share the same Genre.
I did it this way:
List<MediaItem> lItems = ltCOntext.MediaItems.Where(x => x.Genres.Any(y => pGenres.Contains(y))).ToList();
but I get an error
Only primitive types or enumeration types are supported in this context.
The problem is that you are trying to compare complex types in database with a list of complex types in memory, this is not possible. What I suggest doing is converting your pGenres to a list of int by using projection:
List<int> pGenresId = pGenres.Select(p => p.Id).ToList();
Then you can use your query:
List<MediaItem> lItems = ltCOntext.MediaItems
.Where(x => x.Genres.Select(g => g.Id).Any(y => pGenresId.Contains(y))).ToList();
Now Linq-to-entities can convert this into a query by putting the int's of the Id's in the queries.
And if you try this variant :
ICollection<MediaItemGenre> pGenres = mediaItem.Genres;
List<MediaItem> lItems =
ltCOntext.MediaItems
.Where(m => m.Genres
.Any(g =>
mediaItem.Genres
.Select(c=>c.Id).Contains(g.Id))).ToList();
I am using RavenDb in C# web project. I have an object that I need to query its child collection with 1 row per child object and some of the root/parent object properties.
Note: This is not the actual design, just simplified for this question.
public class OrderLine
{
public string ProductName { get; set; }
public int Quantity { get; set; }
public DateTime? ShipDate { get; set; }
}
public class Order
{
public int OrderId { get; set; }
public string CustomerName { get; set; }
public DateTime OrderDate { get; set; }
public List<OrderLine> OrderLines { get; set; }
}
The order with the orderlines is one single document. ShipDate will be updated on each line because not all products are always in stock.
I need to be able to create a list of the last 10 products sent with the following columns:
OrderId
Customer
ProductName
ShipDate
This doesn't work because SelectMany is not supported:
var query = from helper in RavenSession.Query<Order>()
.SelectMany(l => l.OrderLines, (order, orderline) =>
new { order, orderline })
select new
{
helper.order.OrderId,
helper.order.CustomerName,
helper.orderline.ProductName,
helper.orderline.ShipDate
};
var result = query.Where(x => x.ShipDate.HasValue)
.OrderByDescending(x => x.ShipDate.Value).Take(10);
I believe the right thing to do isto create an Index that will flatten out the list but I haven't had any success. I don't believe a Map-Reduce situation will work because as I understand it will effectively does a group by which Reduces the number of documents to less rows (in the index). But in this case, I am trying to expand the number of documents to more rows (in the index).
I would rather not put each OrderLine in a separate document but I do not know what my options are.
Since you want to filter and sort by fields in the subclass, you'll need to make sure all the fields you want are indexed and stored.
public class ShippedItemsIndex
: AbstractIndexCreationTask<Order, ShippedItemsIndex.Result>
{
public class Result
{
public int OrderId { get; set; }
public string CustomerName { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public DateTime ShipDate { get; set; }
}
public ShippedItemsIndex()
{
Map = orders =>
from order in orders
from line in order.OrderLines
where line.ShipDate != null
select new
{
order.OrderId,
order.CustomerName,
line.ProductName,
line.Quantity,
line.ShipDate
};
StoreAllFields(FieldStorage.Yes);
}
}
Then you can project from the index into your results.
var query = session.Query<Order, ShippedItemsIndex>()
.ProjectFromIndexFieldsInto<ShippedItemsIndex.Result>()
.OrderByDescending(x => x.ShipDate)
.Take(10);
var results = query.ToList();
Here is a complete test demonstrating.
I have a List<Order>
public int OrderID { get; set; }
public string CustID { get; set; }
public string Details { get; set; }
I want to write a method that accepts a ID, then searches this List for matching records that have same CustID and returns ORderID and Details in a List<>
This will get a sequence of Order objects that match the criteria:
var ordersIWant = myList.Where(order => order.CustID == "some customer ID");
public List<Order> Get(string id)
{
List<Order> orders = new List<Order>(); // pass this in as a param or globally refer to it
var query = from o in orders
where o.CustID == id
select o;
return query.ToList();
}
Or if you want to specifically return only those two fields maybe something like:
public class Order : IOrderDetails
{
public int OrderID { get; set; }
public string CustID { get; set; }
public string Details { get; set; }
}
public interface IOrderDetails
{
int OrderID { get; set; }
string Details { get; set; }
}
public List<IOrderDetails> Get(string id)
{
List<Order> orders = new List<Order>(); // pass this in as a param or globally refer to it
var query = from o in orders
where o.CustID == id
select o as IOrderDetails;
return query.ToList();
}
Assuming those properties you listed belong to a class.
string searchId="15";
var list = (from item in myList
where item.OrderId == searchId
select new {OrderId= item.OrderId,Details = item.Details }).ToList();
Just wrote that without compiling... good luck.
Since you only wanted OrderID and Details I returned an anonymous object. Could also just return item.