Linq表选择IN可查询的位置

问题描述 投票:0回答:2

我有两节课;第一个是:

public class People
{
   public int Id {get;set;}
   public Dog Dogs {get;set;}
}

public class Dog
{
    public int Id {get;set;}
    public string Name {get; set;}
    public int PeopleId {get;set;}
    public bool IsNewborn {get;set;}
}

Dog类的PeopleId是People类的Id。

现在,使用实体框架,我检索了新生狗的列表:

var AllNB_dogs = _dog_repository.Table;
AllNB_dogs = AllNB_dogs.Where(x => x.IsNewborn );

我现在需要检索的是拥有新生狗的人的列表。

我尝试:

var PeopleWithNB = _people_repository.Table.Where(x => AllNB_dogs.Contains(x.Id));

但是我知道在“包含”中我不能放置一个Int,但是我需要插入一个People对象。

我也尝试:

var PeopleWithNB = _people_repository.Table.Select(x => ...);

但没有成功。有人能帮我吗?还是有另一种方法可以做到这一点?

我正在使用EF Core 2.2。

linq entity-framework-core
2个回答
1
投票

假设您在PeopleDogs之间具有关联,因此可以使用Any

Any

请参见var PeopleWithNB = _people_repository.Table.Where(x => x.Dogs.Any(d => d.IsNewborn)).ToList();


0
投票

根据您的设计,每个人只有一只狗,没有没有狗的人(我敢肯定有很多没有狗的人),也没有不只狗的人。我不知道如果有人卖掉他的狗,你会怎么做。

此外,人物具有属性Relationships in Entity-Framework Core,看来您想设计人物与狗之间的一对多关系。每个人有零只或更多只狗,每只狗完全属于一个人,即具有PeopleId的人。

如果您真的想要一对一的关系(每个人都有一只狗),请参见下文。我将首先处理一对多关系。

一对多

人有零只或更多只狗,每只狗完全属于一个人,即PeopleId所指的狗。

通常情况下,表用多个名词标识,表中的行用单数名词标识。因为“人”一词在解释时有一些问题,所以我将其更改为更标准的名称。对于最终解决方案,您选择的标识符并不重要。最重要的是,每个人都立即理解您的意思。

重写您的课程:

Dogs

在实体框架中,表的列由非虚拟属性表示,虚拟属性表示表之间的关系(一对多,一对一,多对多,.. 。)

请注意,外键是表中的实际列,因此它是非虚拟属性。

多对多部分最好用public class Customer { public int Id {get;set;} public string Name {get; set;} ... // other Customer properties // every Customer has zero or more Dogs (one-to-many) public virtual ICollection<Dog> Dogs {get;set;} } public class Dog { public int Id {get;set;} public string Name {get; set;} public bool IsNewborn {get;set;} ... // Other Dog properties // Every Dog is owned by exactly one Customer, the Customer that OwnerId refers to public int OwnerId {get;set;} public virtual Customer Owner {get; set;} } 而不是Collection<...>表示。原因是实体框架支持集合的所有功能:添加/删除/计数。 IList具有实体框架不支持的功能,那么最好不提供它,您是否同意?

为了完整起见,DbContext:

IList<...>

大多数人直接访问DbContext。看来您有一个存储库类。 las,您忘了提到这堂课。无论如何,您都有类似的功能:

class MyDbContext : DbContext
{
    public DbSet<Customer> Customers {get; set; }
    public DbSet<Dog> Dogs {get; set;}
}

**返回您的问题**

确定,因此您有一个查询以获取几条狗的序列(在本例中为所有新出生的狗),并且您需要拥有这些狗的客户列表。

如果您使用具有适当虚拟关系的实体框架,这很容易:

IQueryable<Customer> Customers = ... // query all Customers
IQueryable<Dog> Dogs = ...           // query all Dogs

换句话说:从狗的序列来看,只保留新生狗。从剩余的每条狗中,选择属性ID,名称。从此狗的所有者中,选择属性ID和名称。

[您看到:通过使用适当的复数和单数名词,并通过使用虚拟关系,查询似乎非常自然。

问题是,如果客户[4]有两只新出生的狗,那么您两次获得此客户。最好查询:

将所有刚出生的狗给我所有顾客。

[只要有一对多的关系,例如带狗的客户,带学生的学校,带产品的订单,那么无论何时想要带子项目的项目,最好从一侧开始(客户)并使用GroupJoin。

// Get all owners of New Born Dogs:
var result = dogs.Where(dog => dog.IsNewBorn)
                 .Select(dog => new
{
    // Select only the Dog properties that you plan to use:
    Id = dog.Id,
    Name = dog.Name,
    ...

    Owner = new
    {
        // Select only the properties that you plan to use:
        Id = dog.Owner.Id,
        Name = dog.Owner.Name,
        ...
    }),
});

换句话说:从每个客户那里获得一些财产,从他拥有的所有狗中,只保留新生的财产。从其余的属性中获取一些属性。最后,只保留至少有一只新生狗的客户。

**,但是我正在使用实体框架CORE! **

我听过一些使用EF-core时无法使用虚拟属性的人的信。在这种情况下,您必须自己加入表格:

从多方面开始:GroupJoin:

var customersWithTheirNewbornDogs = customers.Select(customer => new
{
    // Select only the Customer properties that you plan to use
    Id = customer.Id,
    ...

    NewbornDogs = customer.Dogs.Where(dog => dog.IsNewborn)
                               .Select(dog => new
                               {
                                    Id = dog.Id,
                                    ...

                                    // not needed, you already know the value:
                                    // OwnerId = dog.OwnerId,
                               })
                               .ToList(),
})
// Result: all Customers, each with their newborn Dogs,
// even if the Customer has no newborn Dogs.

// if you only want Customers that have newborn Dogs:
.Where(customer => customer.NewbornDogs.Any());

或者,如果您想从多方面入手:加入

// GroupJoin Customers and newbornDogs
var customersWithTheirNewbornDogs = customers
.GroupJoin(dogs.Select(dog => dog.IsNewborn), 
customer => customer.Id,                 // from every Customer take the Id
dog => dog.OwnerId,                      // from every Dog take the foreign key
(customer, dogsOfThisCustomer) => new    // when they match, take the customer and his Dogs
{                                        // to make one new object
    Id = customer.Id,
    ...

    NewBornDogs = dogsOfThisCustomer.Select(dog => new
    {
         Id = dog.Id,
         ...
    });
});

一对一

如果您的世界上每个人都只有一条狗,没有人没有狗,也没有人有几只狗,那么您可以像上面那样进行加入。(顺便说一句,看看如果您不使用适当的复数形式和单数名词,听起来会有多奇怪?)

var newbornDogsWithTheirOwners = dogs.Where(dog => dog.IsNewborn)
.Join(customers,
dog => dog.OwnerId,                   // from every Dog take the OwnerId,
customer => customer.Id,              // from every Customer take the Id,
(dog, owner) => new                   // when they match, take the dog and the owner
{                                     // to make one new
     Id = dog.Id,
     ...

     Owner = new
     {
          Id = owner.Id,
          ...
     }
});
© www.soinside.com 2019 - 2024. All rights reserved.