我想返回与单个设备相关联的组件列表。我有3个表,组件,设备,EquipmentComponent。
我在数据服务上有一个方法,它应该返回一个组件列表。
apply
我做了一个SQL查询来完成这个:
v = df.apply(foo, axis=1)
v
0 Thank you It is
1 Thank you It is
2 I am surprised So am I
3 I am surprised So am I
4 Hello Nice to meet you
5 Hello Nice to meet you
dtype: object
df['relevantspeeches'] = v
但我不确定如何将此SQL查询转换为LINQ,然后返回组件列表。是否可以仅使用扩展方法?目前我在不使用LINQ的情况下从数据库返回单个组件:
public async Task<IEnumerable<Component>> GetComponentsByEquipmentIdAsync(int equipmentId)
{
using (var ctx = _contextCreator())
{
//query components code
}
}
答案 0 :(得分:1)
稍微依赖于您的实体以及您如何建立M:N关系......
如果您将EF配置为了解M:N关系,那么您可以/应该在任何一侧都有一个导航属性,您可以使用该属性从一个元素从关系的一侧获取到相关元素另一边,反过来......
在代码第一种方法中它看起来像这样:
modelBuilder.Entity<EntityA>().HasMany(e => e.correspondingBs).WithMany(e => e.correspondingAs).Map(e => e.ToTable("AtoBTable").MapLeftKey("aId").MapRightKey("BId"));
在这种情况下,你可以在你的问题的注释中使用像KinSlayerUY提供的选择(EF处理M:N部分并隐藏在引擎盖下处理的映射表)
另一个选择是将映射表视为一个实体本身(如果关系本身具有其他属性,可能你想要这个)
在这种情况下,你最终会得到类似的东西:
ctx.Set<EntityA>().Where(x=>x.id==entityAid).SelectMany(x=>x.correspondingAtoBs.Select(y=>y.correspondingB))
(请注意代码中的拼写错误,我现在手头没有IDE)
答案 1 :(得分:1)
有两种类型的LINQ函数:使用延迟执行的函数和不使用延迟执行函数的函数。
使用延迟执行的函数(Where,Select,GroupBy,Join,...)仅更改IQueryable的表达式。只有在你调用像ToList(),Any(),FirstOrDefault()之类的非延迟函数之后,才能实际执行查询。
异步版本仅对非延迟函数有用。毕竟,有一些东西,你的线程可以做其他事情,而不是等待数据库的结果。
幸运的是,DbSet有等待的异步扩展功能。你可以使用它们。
但是,如果您设置了many-to-many relationship according to entity-framework default conventions,那么您的查询将非常简单。
class Equipment
{
public int Id {get; set;}
...
// every equipment has zero or more Components (many-to-many)
public virtual ICollection<Component> Components {get; set;}
}
class Component
{
public int Id {get; set;}
public string Name {get; set;}
// Every Component belongs to zero or more Equipments (many-to-many)
public virtual ICollection<Equipment> Equipments {get; set;}
}
class MyDbcontext : DbContext
{
public DbSet<Equipment> Equipments {get; set;}
public DbSet<Component> Components {get; set;}
}
这就是所有实体框架需要了解您想要设计多对多关系。您不必提及EquipmentComponent表。实体框架将理解它是需要的,并为您创建它。
返回查询
您希望属于设备的所有组件的所有ComponentIds和ComponentNames都具有Id等于equipmentId
正确设置了多对多,您可以使用ICollections获取数据:
var result = dbContext.Equipments // from all equipment
.Where(equipment => equipment.Id == equipmentId) // take only those with equipmentId
.SelectMany(equipment => equipment.Components // from their components
.Select(component => new
{
Id = component.Id, // select the Id
Name = component.Name, // and the Name
}));
这样做的结果仍然是IQueryable。尚未与数据库进行通信。要执行查询异步,您必须使用非延迟函数
public async Task<IEnumerable<Component>>
GetComponentsByEquipmentIdAsync(int equipmentId)
{
using (var dbContext = new MyDbContext())
{
var result = ... // see above
return await result.ToListAsync();
}
}
如果你真的更喜欢偏离标准实体框架的多对多约定,并且你不想使用ICollections,但设计自己的连接,那么你必须自己做。
使用linq方法语法的内部联接没有问题,但是如果连接三个表,则内部联接看起来很可怕。 See How to perform multiple tables using lambda expressions
因此我将使用查询语法创建IQueryable,然后使用异步函数获取结果:
public async Task<IEnumerable<Component>> GetComponentsByEquipmentIdAsync (int equipmentId)
{
using (var dbContext = new MyDbContext())
{
var result = from equipment in dbContext.Equipments
.Where(equipment => equipment.Id == equipmentId)
join equipmentmodel in dbContext.EquipmentModel
on equipment.Id equals equipmentModel.EquipmentId
join model in dbContext.Models
on equipmentmodel.ModelId equals model.Id
select new
{
Id = component.Id,
Name = component.Name
};
return await result.ToListAsync(); // or whatever non-deferred you want
}