如何使用linq获取两个表的公用表

时间:2019-07-29 12:39:47

标签: c# linq

Data tables

我想将这两个linq查询合并为一个查询 有可能吗?

    var chestProducts = (from w in WareHouse
                                   join c in Chests on w.Id equals c.WareHouseId
                                   join p in Products on c.Id equals p.ContainerId                                    
                                   where (p.IsContainerChest == true && w.Id == 1)
                                   select p
            ).ToList();

    var boxProducts = (from w in WareHouse
                                   join b in Boxes on w.Id equals b.WareHouseId
                                   join p in Products on b.Id equals p.ContainerId                                    
                                   where (p.IsContainerChest != true && w.Id == 1)
                                   select p
            ).ToList();

    var allProducts = chestProducts.AddRange(boxProducts);

我应该使用两个查询吗?

这种关系是健康的吗?

编辑:简化了Boxs和Chests表,它们具有不同的字段

2 个答案:

答案 0 :(得分:3)

尝试一下:

var allProducts = chestProducts.Concat(boxProducts);

或者您也可以使用联盟

var allProducts = Enumerable.Union(chestProducts, boxProducts);

答案 1 :(得分:2)

好的,从您的评论中,我可以看到您首先在代码中使用EF6。在那种情况下,我将使用Table per Hierarchy并将BoxChest放在一个表中(它们仍将是单独的类)。一个(重要的)警告:我已经与EF Core专门合作了一段时间,而我还没有对此进行测试。但是我反复使用了这种模式,效果很好。

您的实体应如下所示:

public class WareHouse
{
  [Key]
  public int Id { get;set; }

  public string Name {get;set;}

  public ICollection<Container> Containers {get;set;}
}

public abstract class Container
{
  [Key]
  public int Id {set;set;}

  public int WareHouseId {get;set;}

  [ForeignKey(nameof(WareHouseId))]
  public WareHouse WareHouse {get;set;}

  public string Name {get;set;}

  public ICollection<Product> Products {get;set;}
}

public class Box : Container
{
  // box specific stuff here
}

public class Chest : Container
{
  // chest specific stuff here
}

public class Product
{
  [Key]
  public int Id {set;set;}

  public int ContainerId {get;set;}

  [ForeignKey(nameof(ContainerId))]
  public Container Container {get;set;}  
}

您的上下文如下:

public class MyContext : DbContext
{
  public virtual DbSet<WareHouse> WareHouses {get;set;}
  public virtual DbSet<Container> Containers {get;set;}
  public virtual DbSet<Product> Products {get;set;}

  protected override void OnModelCreating(ModelBuilder builder)
  {
    // puts the class name in a column, makes it human readable
    builder.Entity<Container>().Hasdiscriminator<string>("Type");

    // i don't think you need to do this, but if it doesn't work try this
    // builder.Entity<Box>().HasBaseType(typeof(Container));
    // builder.Entity<Chest>().HasBaseType(typeof(Container));
  }
}

然后您可以像这样从id = 1的仓库中获取所有产品:

int warehouseId = 1;
Product[] allProducts = myContext.WareHouses
  .Where(wh => wh.Id == warehouseId)
  .SelectMany(wh => wh.Container)
  //.OfType<Box>() if you only want products in boxes
  .SelectMany(wh => wh.Products)
  .ToArray();

我知道您在评论中说过,您倾向于使用linq的lambda语法,但是我觉得我应该指出,您在查询语法示例中进行了许多不必要的联接。如果您正确设置了一切,linq to实体将为您完成所有工作。