一个简单的应用:管理员发布电子文档,若干用户进行签收。
/*
三个 Model,分别是代表电子文档的 EDoc,代表签收的 Sign,代表用户的 User。
EDoc 有创建者导航属性是 User 对象,Sign 有签收者导航属性也是 User 对象。
EDoc 有对应的签收列表导航属性,是 List<Sign> 对象
*/
[Index("Title")]
public class EDoc
{
[Key]
public int Id { get; set; }
[Comment("标题")]
[StringLength(250), Required]
public string Title { get; set; }
[Comment("文档内容")]
public string Content { get; set; }
[Comment("发布的用户Id")]
public int CreaterId { get; set; }
[Comment("发布的用户")]
public User Creater { get; set; }
[Comment("创建时间")]
public DateTime CreateDateTime { get; set; } = DateTime.Now;
[Comment("签收列表")]
public List<Sign> SignList { get; set; } = new();
}
public class Sign
{
[Key]
public int Id { get; set; }
[Comment("所属的 EDoc 对象 Id")]
public int EDocId { get; set; }
[Comment("所属的 EDoc 对象")]
public EDoc EDoc { get; set; }
[Comment("签收的用户Id")]
public int SignerId { get; set; }
[Comment("签收的用户")]
public User Signer { get; set; }
[Comment("签收的内容")]
public string Content { get; set; }
[Comment("签收时间")]
public DateTime? SignTime { get; set; }
}
[Index("Username")]
public class User
{
[Key]
public int Id { get; set; }
[Comment("显示名称")]
[StringLength(50), Required]
public string DisplayName { get; set; }
[StringLength(50), Required]
public string Username { get; set; }
[StringLength(128), Required]
public string Password { get; set; }
[Comment("是否禁用")]
public bool Forbid { get; set; }
[Comment("是否是管理员")]
public bool IsAdmin { get; set; }
}
很简单是吧?
用户登录后,要获取用户需要签收的文档对象:
// _db 为 DBContext,curUserId 是当前登录用户的 Id
//主语句:
var _q = _db.EDoc.OrderByDescending(x => x.CreateDateTime).Where(x => x.SignList.Any(y => y.SignerId == curUserId));
//因为要分页,所以先获取总数:
int recordCount = _q.Count();
//接下来再获取分页的列表:
_q.Skip(...).Take(...).ToList();
整个过程的示意代码步骤如上所示。
数据量也不大,EDoc 表 1.5W,Sign 表 10W
当执行 _q.Count() 时生成如下 SQL 语句:
SELECT COUNT(*)
FROM "EDocs" AS "e"
WHERE EXISTS (
SELECT 1
FROM "Signs" AS "s"
WHERE ("e"."Id" = "s"."EDocId") AND ("s"."SignerId" = @curUserId))
DBContext 分别使用 EntityFrameworkCore.SQLServer 和 EntityFrameworkCore.Sqlite
SQLServer 正常,执行时间 50ms 以下,而切换到 Sqlite 时,执行时间竟然将近 1 分 30 秒!
两个数据库都是通过 EntityFrameworkCore.Tools 生成的,结构和数据相同,主键索引等也都正常。
请教各位看看是哪里出现了问题,是不是我的 Linq 语句写得不对,还是需要对 Sqlite 优化的问题?