【问题标题】:Multiple cross reference table joins in linqlinq中的多个交叉引用表连接
【发布时间】:2014-03-17 09:58:20
【问题描述】:

自从我试图提出一种优化的查询方式以来,这一直困扰着我。

假设我有 3 个交叉引用表,它们共享一个公共列,该公共列将对包含更多信息的主表进行最终连接。

例如:

假设我有以下内容:

 Customers //properties: ID, Name, Address
 IEnumberable<CustomerSports> //properties: CustomerID, SportsID
 IEnumberable<CustomerLocation> //properties: CustomerID, LocationID
 IEnumberable<CustomerPets> //properties: CustomerID, PetsID

所以我可以进行如下查询:

请给我一份居住在纽约 (CustomerLocation) 的客户名单,其中包括打曲棍球、橄榄球、足球 (CustomerSports)... 并养狗和猫 (CustomerPets)。查找表可以为空,因此客户可以进行运动,但没有宠物。

然后,当我获得客户列表时,我将加入客户表中的公共列 (CustomerID) 以检索 ID、名称和地址。

我正在考虑让客户表在每次查找时加入,然后进行联合以获取客户列表,但我不知道这是否是正确的做法。

【问题讨论】:

  • 您想要拥有宠物或从事运动的客户(左外连接),还是只想要拥有/拥有所有这些东西的客户? (您在问题中使用了 AND 一词,但您提到一些客户可以做一个但不能做另一个的事实让我认为您的意思是 OR)。
  • 浏览这里可能会带来一些见解。 msdn.microsoft.com/en-us/library/bb399397%28v=vs.110%29.aspx

标签: c# linq cross-reference


【解决方案1】:

只要您正确设置了设计,那么每个Customer 都应该有一个Sports 集合、一个Pets 集合和一个Locations(除非最后一个是一对一连接?) .

如果建立了这些关系,那么您可以如下查询:

var sports = new string[] { "lacrosse", "football", "soccer" };
var pets = new string[] { "cat", "dog" };
var locations = new string[] { "new york" };
var sportyPetLoversInNewYors = db.Customers
    .Where(cust => sports.All(sport => cust.Sports.Any(custSport => custSport.Name == sport)))
    .Where(cust => pets.All(pet => cust.Pets.Any(custPet => custPet.Name == pet)))
    .Where(cust => locations.All(loc => cust.Locations.Any(custLoc => custLoc.Name = loc)))
    // could customise the select here to include sub-lists or whatever
    .Select();

这假设您只想要满足所有 6 个条件的人。如果您希望人们至少喜欢其中一项运动,至少拥有其中一只宠物,并且(假设您使用多个位置)至少在其中一个位置,Where 表达式将更改如下

.Where(cust => cust.Sports.Any(custSport => sports.Contains(custSport.Name)))

如果您需要进一步解释,请告诉我。

【讨论】:

  • 我意识到这是我真正的解决方案。与加入相比,我对过滤器有更多的控制权。当我尝试加入时,它会为所有表做一个内部。但问题是,我需要它基于 3 个数据源进行过滤,如果有任何运动、任何宠物或任何位置。如果我加入了,其中任何一个都是空的,它会返回一个空集。
  • 这比使用 JOIN CPU/Memory 成本要好得多,因为它编译成使用 EXISTS 的 SQL(例如可以使用 LINQpad 检查)
【解决方案2】:

这样做的一种方法,如果我理解你的追求。允许多项运动和多只宠物,或者没有。

        var contacts = from cust in customer
                       join sport in sports on cust.CustomerID equals sport.CustomerID into multisport from sport in multisport.DefaultIfEmpty()
                       join loc in location on cust.CustomerID equals loc.CustomerID
                       join pet in pets on cust.CustomerID equals pet.CustomerID into multipet from pet in multipet.DefaultIfEmpty()

                       select new
                       {
                           cust.CustomerID,
                           multisport,
                           loc.LocationID,
                           multipet
                       };

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-08
    • 1970-01-01
    • 1970-01-01
    • 2017-01-26
    • 1970-01-01
    相关资源
    最近更新 更多