我有两节课;第一个是:
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。
假设您在People
和Dogs
之间具有关联,因此可以使用Any
:
Any
请参见var PeopleWithNB = _people_repository.Table.Where(x => x.Dogs.Any(d => d.IsNewborn)).ToList();
根据您的设计,每个人只有一只狗,没有没有狗的人(我敢肯定有很多没有狗的人),也没有不只狗的人。我不知道如果有人卖掉他的狗,你会怎么做。
此外,人物具有属性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,
...
}
});