首页 > 解决方案 > 使用实体框架中的各种表实现“连接”

问题描述

我有三张桌子:

材料

  1. ID
  2. 标题
  3. 内容

喜欢

  1. ID
  2. 材质 ID
  3. 用户身份
  4. 喜欢

访客

  1. ID
  2. 用户身份
  3. 材质 ID
  4. 日期
  5. 现在读

我想得到一个像这样的对象:

  1. 标题
  2. 内容
  3. 点赞数
  4. 计数访客

我尝试执行以下操作:

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()”,将在本地进行评估。

标签: c#sql-serverentity-frameworklinqentity-framework-core

解决方案


如果您使用实体框架,请考虑使用 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。


推荐阅读