【发布时间】:2019-11-29 18:42:27
【问题描述】:
我不能相信我是第一个遇到这个问题的人,但没有在网上找到任何类似的讨论。
这里是简单的完整代码示例:
using SQLite.CodeFirst;
using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Entity entity = new Entity();
Guid id = entity.Id;
using (var context = new MyDbContext())
{
context.Entities.Add(entity);
context.SaveChanges();
// this finds an entry
var item = context.Entities.Find(id);
}
using (var context = new MyDbContext())
{
// here it returns null
var item = context.Entities.Find(id);
}
}
}
public class MyDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer(new SqliteDropCreateDatabaseWhenModelChanges<MyDbContext>(modelBuilder));
}
public MyDbContext() : base("MyConnection") {}
public DbSet<Entity> Entities { get; set; }
}
public class Entity
{
[Key]
public Guid Id { get; set; } = Guid.Parse("D46D98F3-C262-468A-9C28-83D81080CF18");
public string Name { get; set; } = "Test";
}
}
问题已在代码中标记。第一个“查找”返回新添加的条目。
但是在获取上下文的新实例时,找不到条目。
即使,如果我第二次运行应用程序,跳过将条目添加到表中的代码,它也不会找到该项目。问题似乎不在于“查找”方法,因为 T 已经尝试了其他几个具有相同结果的 linq 语句。
当我在搜索之前第一次从表中获取所有项目时,它适用于“查找”,但不适用于 linq。
示例如下:
using (var context = new MyDbContext())
{
// this returns all items
var allItems = context.Entities.ToArrayAsync().Result;
// this finds the item
var item1 = context.Entities.Find(id);
// this doesn't find the item
var item2 = context.Entities.Where(x => x.Id == id).FirstOrDefault();
}
using (var context = new MyDbContext())
{
// this doesn't find the item
var item1 = context.Entities.Find(id);
// this also doesn't find the item
var item2 = context.Entities.Where(x => x.Id == id).FirstOrDefault();
}
有人解释一下吗?将键更改为 string 或 int 而不是 GUID,它可以按预期工作。
【问题讨论】:
-
SQLite 不支持 GUID,您必须将值存储为字符串或 BLOB。 GUID 必须存储为字符串或 BLOB。不过,您还没有提供表模式,因此很难重现任何内容。您是否尝试在关闭应用程序后读取 SQLite 文件? EF 不与数据库本身通信,它使用 ADO.NET 和配置的提供程序
-
I can't beleave I'm the first person running into that problem,这是一个非常强烈的指标,表明问题出在代码中,而不是库中。之前有关于GUID in SQLite 的讨论。 GUID 是可怕的键,尤其是在像 SQLite 这样的嵌入式数据库中。它们占用的空间是 64 位长度的 2 或 4 倍,除非您使用顺序 GUID 算法,否则它们会导致碎片 -
您也没有提到您使用 SQLite.CodeFirst。是不是因为配置错误或内存中的连接字符串,每个 DbContext 实例都会创建一个 new 数据库?您是否尝试在运行程序时或在程序完成后从数据库中读取?如果您配置预写日志记录,您可以让多个应用程序使用 SQLite 客户端应用程序从同一个数据库中读取数据
-
看起来以前有关于 SQLite、GUID 和 EF like this one from 2014 的问题。当时,问题是由 SQLite 自己的 ADO.NET 提供程序中的错误引起的。您使用的是哪个提供商?你的连接字符串是什么样的?
-
问题是因为 SQLite 无法处理 GUID,所以 GUID 正在被转换为 BLOB。这会导致从 LINQ 生成的 SQL 查询失败。这就解释了为什么将它全部加载到内存中,然后查询它的工作原理,因为一旦加载到内存中,它就可以正确比较 GUID
标签: c# entity-framework sqlite