c# - 使用实体框架中的各种表实现“连接”
问题描述
我有三张桌子:
材料:
- ID
- 标题
- 内容
喜欢:
- ID
- 材质 ID
- 用户身份
- 喜欢
访客:
- ID
- 用户身份
- 材质 ID
- 日期
- 现在读
我想得到一个像这样的对象:
- 标题
- 内容
- 点赞数
- 计数访客
我尝试执行以下操作:
from mat in ctx.materials
let visitors = mat.VisitorsCollection.Where(x=>x.ReadNow).Count()
let likes = mat.LikesCollection.Where(x=>x.IsLiked).Count()
let iliked = mat.LikesCollection.Where(x=>x.UserID == myID && x.IsLiked).Any()
select new {
Material = mat,
Visitors = visitors,
Likes = likes,
Liked = iliked
}
我选择了一些材料,实体框架分别接收访问者数量等数据。
我还尝试了以下方法:
from mat in ctx.materials
join lik in ctx.Likes.Where(x=>x.UserID == myID && x.IsLiked) on map.ID equals lik.MaterialID
select new {
Material = mat,
Liked = lik.Any()
}
但现在发生错误:
Microsoft.EntityFrameworkCore.Query:警告:无法翻译 LINQ 表达式“Any()”,将在本地进行评估。
解决方案
如果您使用实体框架,请考虑使用 ICollections,而不是自己执行连接。
您有一个序列,Materials
其中 everyMaterial
有零个或多个Likes
和零个或多个Visitors
,都是一对多关系,使用外键 to Material
。
如果您遵循实体框架代码优先约定,您将拥有类似于以下的类
class Material
{
public int Id {get; set;}
public string Title {get; set;}
public string Content {get; set;}
// every Material has zero or more Likes (one-to-many)
public virtual ICollection<Like> Likes {get; set;}
// every Material has zero or more Visitors (one-to-many)
public virtual ICollection<Visitor> Visitors {get; set;}
}
喜欢和访客:
class Like
{
public int Id {get; set;}
public bool IsLiked {get; set;}
...
// every Like belongs to exactly one Material, using foreign key
public int MaterialId {get; set;}
public virtual Material Material {get; set;}
}
class Visitor
{
public int Id {get; set;}
...
// every Visitor belongs to exactly one Material, using foreign key
public int MaterialId {get; set;}
public virtual Material Material {get; set;}
}
这就是实体框架检测一对多关系所需的全部内容。您可能需要不同的表名或列的不同标识符。在这种情况下,需要属性或流畅的 API
在实体框架中,表的列由非虚拟属性表示。虚拟属性表示表之间的关系(一对多、多对多等)
一旦你正确地得到了你的类定义,你的查询就很简单并且非常直观:
要求:
从我收集的材料中,从每个材料中给我,标题,内容,它拥有的喜欢的数量和它拥有的访问者数量:
var result = myDbContext.Materials
.Where(material => ...) // only if you don't want all Materials
.Select(material => new // from every Material make one new object
{ // containing the following properties
Title = material.Title,
Content = material.Content,
// if you want any information of the likes of this material, use property Likes
LikeCount = material.Likes
.Where(like => like.IsLiked) // optional, only if you don't want all likes
.Count(),
NrOfVisitors = material.Visitors
.Where(visitor => ...) // only if you don't want all visitors
.Count(),
});
换句话说:从我完整的材料集合中,只保留那些材料......从剩余的每个材料中,制作一个新对象:
- 标题是材料的标题
- 内容是材料的内容
- LikeCount 是该材料的点赞数(具有真正的 IsLiked)
- NrOfVisitors 是该材料的访问者数量(即...)
实体框架知道您的关系,并且知道需要 GroupJoin。
推荐阅读
- javascript - 为什么 (function() { return this; }).call('string literal') 返回 [String: 'string literal'] 而不是 'string literal'?
- kubernetes - 如何在不安全的 kubernetes api 服务器端口上强制执行身份验证和授权模块
- ios - 使用 Xcode 11 将 SPM 下载的包保存到项目 GIT 中
- guzzle - guzzle3 添加令牌发布请求
- html - 在 Safari 中自动播放音频文件
- ios - 由于涉嫌 UISearchDisplayController,从 TestFlight 安装的应用程序崩溃
- php - Stackdriver 错误报告中缺少默认 GAE 服务
- oracle - 如何缩短正则表达式
- python - SageMaker AWS 二进制文本分类
- python - 如何在不更改元数据的情况下解压缩 zip 文件?