I want to create a lambda expression to query a collection by a collection
In a EF code first environment, I have the following data objects
I have a class named price
public class Price
{
public int Id { get; set; }
public string DisplayName { get; set; }
public double Amount { get; set; }
public bool IsActive { get; set; }
public int ItemId { get; set; }
[ForeignKey("ItemId")]
public virtual Item Item { get; set; }
public ICollection<PriceOption> PriceOptions { get; set; }
}
And a related class named
public class PriceOption
{
public int Id { get; set; }
public int PriceId { get; set; }
[ForeignKey("PriceId")]
public virtual Price Price { get; set; }
public int OptionId { get; set; }
[ForeignKey("OptionId")]
public virtual Option Option { get; set; }
}
I have two search criteria
int ItemId
List<int> optionIds
I want to create a lambda expression to select all prices that are equil to the ItemId (easy) and where the PriceOptions
collection contains all of the optionIds.
The Idea is something like this but of course this it just to show what I am trying to achive.
List<Price> prices = _priceRepository.FindAll().Where(x => x.ItemId == item.Id && x.PriceOptions.All(y => y.OptionId == optionIds)).ToList();
Thank you for your help
Earl
The following LINQ query based on Contains and Count methods produces a simpler (thus eventually faster) SQL query:
var matchCount = optionIds.Count;
var prices = _priceRepository.FindAll()
.Where(p => p.ItemId == ItemId &&
p.PriceOptions.Count(po => optionIds.Contains(po.OptionId)) == matchCount)
.ToList();
Related
My scenario: Users will be able to create lists and add items to these lists. What I want to do is to find the items in the lists created by the users at most.
Item Entity
public class Item:BaseEntity
{
public string Name { get; set; }
public decimal Price { get; set; }
public decimal DiscountedPrice{ get; set; }
public virtual ICollection<ItemList> ItemLists { get; set; }
}
Item List Entity
public class ItemList:BaseEntity
{
public string Name { get; set; }
public string Description { get; set; }
public int UserId { get; set; }
public ICollection<Item> Items { get; set; }
[ForeignKey("UserId")]
public virtual User User { get; set; }
}
User Entity
public class User:BaseEntity
{
public string Name { get; set; }
public string Surname { get; set; }
public string Gsm { get; set; }
public string Email { get; set; }
public virtual ICollection<ItemList> ItemLists{ get; set; }
}
my DTO
public class TopItemsForUsers
{
[BsonRepresentation(BsonType.ObjectId)]
[BsonId]
public string ItemId { get; set; }
public string UserId { get; set; }
public int Quantity { get; set; }
}
My Item repository
var query = _context.Items.Include(l => l.ItemLists)
.GroupBy(g => g.ItemLists)
.Select(z => new TopItemsInLists { ItemId = z.Key.ToString(), Quantity = z.Count() })
.OrderByDescending(z => z.Quantity)
.Take(10);
I want to get products that are very present in users' lists
Where am I doing wrong? If anyone has any other suggestions
Try this query. I hope I understand question correctly.
var query =
from u in _context.Users
from il in u.ItemLists
from i in il.Items
group i by new { UserId = u.Id, ItemId = i.Id } into g
select new TopItemsInLists
{
UserId = g.Key.UserId.ToString(),
ItemId = g.Key.ItemId.ToString(),
Quantity = g.Count()
};
query = query
.OrderByDescending(z => z.Quantity)
.Take(10);
I have a product that have list of price, Can i order by price?
public class Product
{
public int Id { get; set; }
public string Title { get; set; }
public IList<ProductPrice> ProductPrices{ get; set; }
}
public class ProductPrice
{
public int Id { get; set; }
public int Degree{ get; set; }
public int Price{ get; set; }
}
I use this code.but don't ordered
_db.Products.Select(m=>m.ProductPrices.OrderBy(o=>o.Price))
You don't need Select, juste call OrderBy and Max directly
var listSorted = _db.Products.OrderBy(p => p.ProductPrices.Max(pp => pp.Price))
If you want to order products by the maximum product price then do this:
_db.Products.OrderBy(p => p.ProductPrices.Max(pp => pp.Price))
I have two lists have the same properties and I want to compare the data between them, I need three list shown in the view
NewlyAdded Employee (Done)
Deleted Employee (Done)
Common Employee (Done)
Updated Employee (Don't know how)
I have make the first 3 lists but I don't know how I can get the updated data Then I can deploy the changes to the destEmps so anyone can help me?
public class srsEmployee
{
public int Id { get; set; }
public string Name { get; set; }
public string EmpCode { get; set; }
public Nullable<decimal> Salary { get; set; }
public Nullable<system.datetime> StartDate { get; set; }
public Nullable<system.datetime> BOD { get; set; }
public int DepartmentId { get; set; }
public bool Active { get; set; }
public virtual srsDepartment srsDepartment { get; set; }
}
public class destEmployee
{
public int Id { get; set; }
public string Name { get; set; }
public string EmpCode { get; set; }
public Nullable<decimal> Salary { get; set; }
public Nullable<system.datetime> StartDate { get; set; }
public Nullable<system.datetime> BOD { get; set; }
public int DepartmentId { get; set; }
public bool Active { get; set; }
public virtual destDepartment destDepartment { get; set; }
}
And these are the queries I used to get 3 lists:
var Common = destEmps.Where(n => srsEmps.Any(o => o.EmpCode == n.EmpCode)).ToList();
var Deleted = srsEmps.Where(o => !destEmps.Any(n => n.EmpCode == o.EmpCode)).ToList();
var NewlyAdded = destEmps.Where(n => !srsEmps.Any(o => o.EmpCode == n.EmpCode)).ToList();
var Updated =
from d in destEmps
join c in srsEmployee
on c.Id equals d.Id
where d.Name != c.Name || d.EmpCode != c.EmpCode ..........
select d;
foreach(var element in destEmps)
{
var oldValue = srsEmployee.First(t => t.Id == element.Id);
element.Name = oldValue.Name;
.....
}
You can create a method to generate Hashes of Employee class by using all it's properties, then the elements with same Id but different Hashes will be the elements that got updated.
You can generate a hash using the accepted answer from this link Generate hash of object consistently
P.S. I think you should use the same class for Source and Destination list.
I suggest you create an Equals method in your Employee class, and then use that to compare
public bool Equals(Employee other)
{
if (other == null)
{
return false;
}
else
{
// Do your equality test here.
return (this.ID = other.ID &&
this.Name = other.Name);
// etc...
}
}
You can then use it to find all the items in one where the other list contains an item that is equal.
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.
I have two tables/Entities
public class Attribute
{
public int Id { get; set; }
public string Name { get; set; }
public string Details { get; set; }
public bool Inactive { get; set; }
public virtual ICollection<Item> Items{ get; set; }
}
public class Item
{
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateModified { get; set; }
public virtual ICollection<Attribute> Attributes { get; set; }
}
I am trying to figure out the Linq query to retrieve all of the attribute names for an item ID where the attributes Inactive status is set to false. The attribute count could be 0 to 20.
The following should give you all of the attribute names for the item with the specified ID.
var selectedId = 1; // The item ID you are looking for
var attrNames = items
.Where(i => i.Id == selectedId)
.SelectMany(x => x.Attributes)
.Where(a => !a.Inactive)
.Select(a => a.Name);