Linq query with two many-many relationships
I have the following entities set up which I am trying to query:
- Store
- StoreCapability. A store can have multiple capabilities (e.g. sells chocolate, is big) - but is not required to have any.
- Offers. An offer can require multiple store capabilities in order to be valid, but no requirements are required.
Store -[m2m]- StoreCapability -[m2m]- Offer
So there are five tables involved.
I would like to be able to obtain the following using linq:
- Given an offer, a list of stores which it is valid for
- Given a store, a list of offers available
Using SQL it would be possible to join from Store, to StoreCapability, to Offer and then group by offer and store and only obtain the stores having count() equal to the number of requirements an offer has. However I don't know where to start with this with Linq, because the many-many tables are hidden away from me by the Entity framework. Please can anyone help with how I can do this?
The SQL could be something similar to this:
SELECT Offers.Id, offers.Name, Stores.Id, Stores.Name FROM Offers
--join to the capabilities that this offer needs
LEFT OUTER JOIN StoreCapabilityOffers offerRequirements ON Offers.Id = offerRequirements.Offer_Id
--join to stores which have capability
LEFT OUTER JOIN StoreCapabilities ON offerRequirements.StoreCapability_Id = StoreCapabilities.Id
--join to stores
LEFT OUTER JOIN StoreStoreCapabilities storeCap ON offerRequirements.StoreCapability_I开发者_如何学运维d = storeCap.StoreCapability_Id
LEFT OUTER JOIN Stores on storeCap.Store_Id = Stores.Id
GROUP BY Offers.Id, offers.Name, Stores.Id, Stores.Name
-- get stores who have the right number of capabilities so all requirements are all met
HAVING COUNT(*) = (
select COUNT(*) from StoreCapabilityOffers x where x.Offer_Id = Offers.Id
)
Entities below:
public class Store
{
public int Id { get; set; }
public virtual ICollection<StoreCapability> Capabilities { get; set; }
}
public class StoreCapability
{
public int Id { get; set; }
public virtual ICollection<Store> Stores { get; set; }
public virtual ICollection<Offer> Offers { get; set; }
}
public class Offer
{
public int Id { get; set; }
public virtual ICollection<StoreCapability> StoreCapabilityRequirements { get; set; }
}
I think something like this should work:
Given an offer, a list of stores which it is valid for:
var stores = from o in context.Offers
from c in o.StoreCapabilityRequirements
from s in c.Stores
where o.Id == 1
select s;
Given a store, a list of offers available:
var offers = from s in context.Stores
from c in s.Capabilities
from o in c.Offers
where s.Id == 1
select o;
精彩评论