如何执行两个集合的连接并填充导航属性
How to perform a join of two sets and populate navigation properties
假设我有两个 类、Teapot
和 Cup
:
public class Teapot
{
[Key]
[Column("Id", TypeName = "int")]
public int Id { get; set; }
public int MaterialId { get; set; }
public int ColorId { get; set; }
[ForeignKey("MaterialId")]
public virtual Material Material { get; set; }
[ForeignKey("ColorId")]
public virtual Color Color { get; set; }
}
和
public class Cup
{
[Key]
[Column("Id", TypeName = "int")]
public int Id { get; set; }
public int MaterialId { get; set; }
public int ColorId { get; set; }
[ForeignKey("MaterialId")]
public virtual Material Material { get; set; }
[ForeignKey("ColorId")]
public virtual Color Color { get; set; }
}
这是我的视图模型:
namespace ViewModel.Data
{
public class TeapotsWithInfo
{
public Model.Data.Teapot Teapot { get; set; }
public Model.Data.Cup Cup { get; set; }
}
}
对于我的 ViewModel
,我需要对 MaterialId 和 ColorId 执行连接,并包含一些导航属性,例如 Teapot.Material.Manufacturer
。所以,我尝试了以下查询:
这会抛出 "LINQ to Entities only supports casting EDM primitive or enumeration types"
(from t in db.Teapots
join c in db.Cups
on new { t.MaterialId, t.ColorId } equals new { c.MaterialId, c.ColorId }
where t.Id == id
select new ViewModel.Data.TeapotsWithInfo { Teapot = t, Cup = c })
.Include(t => t.Material.Manufacturer).SingleOrDefault();
这好像忽略了Include
(from t in db.Teapots.Include(t => t.Material.Manufacturer)
join c in db.Cups
on new { t.MaterialId, t.ColorId } equals new { c.MaterialId, c.ColorId }
where t.Id == id
select new ViewModel.Data.TeapotsWithInfo { Teapot = t, Cup = c }).SingleOrDefault();
现在我在这里找到了一些建议枚举然后执行另一个的答案select,但我宁愿一次性捕获数据。
您在包含导航属性时遇到困难,因为带有连接或投影的查询会忽略预加载(请参阅 this)。
不幸的是,您将需要做您似乎在避免的事情:首先从数据库中提取数据,然后执行额外的 select 来构建您的 ViewModel(它将从原始文件中加载关系询问)。但是,额外的 select 应该是一个相当微不足道的操作,因为您没有从数据库执行额外的负载,并且枚举应该只包含一个项目。
(from t in db.Teapots.Include(t => t.Material.Manufacturer)
join c in db.Cups
on new { t.MaterialId, t.ColorId } equals new { c.MaterialId, c.ColorId }
where t.Id == id
select new
{
Teapot = t,
Cup = c,
Material = t.Material,
Manufacturer = t.Material.Manufacturer,
})
.AsEnumerable()
.Select(a => new ViewModel.Data.TeapotsWithInfo
{
Teapot = a.Teapot,
Cup = a.Cup
})
.SingleOrDefault();
来源
假设我有两个 类、Teapot
和 Cup
:
public class Teapot
{
[Key]
[Column("Id", TypeName = "int")]
public int Id { get; set; }
public int MaterialId { get; set; }
public int ColorId { get; set; }
[ForeignKey("MaterialId")]
public virtual Material Material { get; set; }
[ForeignKey("ColorId")]
public virtual Color Color { get; set; }
}
和
public class Cup
{
[Key]
[Column("Id", TypeName = "int")]
public int Id { get; set; }
public int MaterialId { get; set; }
public int ColorId { get; set; }
[ForeignKey("MaterialId")]
public virtual Material Material { get; set; }
[ForeignKey("ColorId")]
public virtual Color Color { get; set; }
}
这是我的视图模型:
namespace ViewModel.Data
{
public class TeapotsWithInfo
{
public Model.Data.Teapot Teapot { get; set; }
public Model.Data.Cup Cup { get; set; }
}
}
对于我的 ViewModel
,我需要对 MaterialId 和 ColorId 执行连接,并包含一些导航属性,例如 Teapot.Material.Manufacturer
。所以,我尝试了以下查询:
这会抛出 "LINQ to Entities only supports casting EDM primitive or enumeration types"
(from t in db.Teapots join c in db.Cups on new { t.MaterialId, t.ColorId } equals new { c.MaterialId, c.ColorId } where t.Id == id select new ViewModel.Data.TeapotsWithInfo { Teapot = t, Cup = c }) .Include(t => t.Material.Manufacturer).SingleOrDefault();
这好像忽略了
Include
(from t in db.Teapots.Include(t => t.Material.Manufacturer) join c in db.Cups on new { t.MaterialId, t.ColorId } equals new { c.MaterialId, c.ColorId } where t.Id == id select new ViewModel.Data.TeapotsWithInfo { Teapot = t, Cup = c }).SingleOrDefault();
现在我在这里找到了一些建议枚举然后执行另一个的答案select,但我宁愿一次性捕获数据。
您在包含导航属性时遇到困难,因为带有连接或投影的查询会忽略预加载(请参阅 this)。
不幸的是,您将需要做您似乎在避免的事情:首先从数据库中提取数据,然后执行额外的 select 来构建您的 ViewModel(它将从原始文件中加载关系询问)。但是,额外的 select 应该是一个相当微不足道的操作,因为您没有从数据库执行额外的负载,并且枚举应该只包含一个项目。
(from t in db.Teapots.Include(t => t.Material.Manufacturer)
join c in db.Cups
on new { t.MaterialId, t.ColorId } equals new { c.MaterialId, c.ColorId }
where t.Id == id
select new
{
Teapot = t,
Cup = c,
Material = t.Material,
Manufacturer = t.Material.Manufacturer,
})
.AsEnumerable()
.Select(a => new ViewModel.Data.TeapotsWithInfo
{
Teapot = a.Teapot,
Cup = a.Cup
})
.SingleOrDefault();
来源