[英]SQLite EF6 Async API throws InvalidCastException
I'm new to entity framework and try to use it with SQLite. 我是实体框架的新手,并尝试将其与SQLite结合使用。 I've a working setup if I don't use the async API. 如果我不使用异步API,则可以进行设置。
In my simplified szenario are only two tables containing a one-to-many relationship. 在我的简化版本中,只有两个表包含一对多关系。 DB setup and insertion of values works fine. 数据库设置和值插入工作正常。 Query is a problem. 查询是一个问题。
Here is the simplified code: 这是简化的代码:
var connectionStringBuilder = new SQLiteConnectionStringBuilder { DataSource = dbFile, ForeignKeys = true };
using (var connection = new SQLiteConnection { ConnectionString = connectionStringBuilder.ConnectionString })
{
await connection.OpenAsync();
// query data
using (var context = new TestContext(connection, contextOwnsConnection: false))
{
var xQuery = context.Xs.Include(item => item.Ys);
var syncX = xQuery.First(); // works fine
var asyncX = await xQuery.FirstAsync(); // throws InvalidCastException
}
}
Why does the call to FirstAsync()
throws an exception while First()
doesn't? 为什么对FirstAsync()
的调用会引发一个异常,而对FirstAsync()
First()
却没有?
The same happens using SingleAsync()
and ToListAsync()
. 使用SingleAsync()
和ToListAsync()
发生相同的情况。 Currently I'm of the opinion that this happens on all async calls. 目前,我认为这会在所有异步调用中发生。
Removing the Include(...)
clause from query will fix the problem but forces a second database query on access to the property. 从查询中删除Include(...)
子句将解决此问题,但在访问属性时强制执行第二次数据库查询。
To avoid hints like "you're calling First
and FirstAsync
on the same query object...": NO. 为避免出现诸如“您正在同一查询对象上调用First
和FirstAsync
...”的提示:否。 The problem still occurs if I only call ...Async()
without calling a synchronous method first. 如果我只调用...Async()
而不先调用同步方法,则仍然会出现问题。 That's just for clearification. 这只是为了澄清。
I'm using a WinForms application .Net 4.7.1, EF6 (by adding System.Data.SQLite v1.0.108 via Nuget). 我正在使用WinForms应用程序.Net 4.7.1,EF6(通过通过Nuget添加System.Data.SQLite v1.0.108)。
The complete code to reproduce the problem: 重现问题的完整代码:
private async void OnClick(object sender, EventArgs e)
{
var dbFile = "test.sqlite";
if (File.Exists(dbFile)) File.Delete(dbFile);
SQLiteConnection.CreateFile(dbFile);
var connectionStringBuilder = new SQLiteConnectionStringBuilder { DataSource = dbFile, ForeignKeys = true };
using (var connection = new SQLiteConnection { ConnectionString = connectionStringBuilder.ConnectionString })
{
await connection.OpenAsync();
// setup database
using (var context = new TestContext(connection, contextOwnsConnection: false))
{
await context.Database.ExecuteSqlCommandAsync("CREATE TABLE X (Id VARCHAR2 PRIMARY KEY);");
await context.Database.ExecuteSqlCommandAsync("CREATE TABLE Y (Id VARCHAR2 PRIMARY KEY, XId VARCHAR2 NOT NULL, FOREIGN KEY (XId) REFERENCES X(Id));");
var x0 = new X { Id = "X0" };
var y0 = new Y { Id = "Y0", XId = x0.Id }; // Currently I don't know why using the navigation property 'X = x0' isn't working but the XId will work.
var y1 = new Y { Id = "Y1", XId = x0.Id }; // Currently I don't know why using the navigation property 'X = x0' isn't working but the XId will work.
x0.Ys.Add(y0);
x0.Ys.Add(y1);
context.Xs.Add(x0);
context.Ys.Add(y0); // not needed but for safety :-)
context.Ys.Add(y1); // not needed but for safety :-)
await context.SaveChangesAsync();
}
// query data
using (var context = new TestContext(connection, contextOwnsConnection: false))
{
var xQuery = context.Xs.Include(item => item.Ys);
var syncX = xQuery.First(); // works fine
var asyncX = await xQuery.FirstAsync(); // throws InvalidCastException
}
}
}
Using the following model classes: 使用以下模型类:
public class TestContext : DbContext
{
public TestContext(DbConnection existingConnection, bool contextOwnsConnection = true) :
base(existingConnection, contextOwnsConnection)
{
}
public DbSet<X> Xs { get; set; }
public DbSet<Y> Ys { get; set; }
}
[Table("X")]
public class X
{
public X()
{
// ReSharper disable once VirtualMemberCallInConstructor
this.Ys = new HashSet<Y>();
}
[Column("Id")]
[Key, Required]
public string Id { get; set; }
public virtual ICollection<Y> Ys { get; set; }
}
[Table("Y")]
public class Y
{
[Column("Id")]
[Key, Required]
public string Id { get; set; }
[Column("XId")]
[Required]
public string XId { get; set; }
[ForeignKey("XId")]
public virtual X X { get; set; }
}
I'm sorry, I can't write comments. 抱歉,我无法发表评论。
Your problem is very interesting, the first thought I had was that the types do not match, because I remembered exactly what FirstAsync takes IQueryable, and if I do include something the type of request is IIncludeableQueryable, but I tested my guess and looked at the implementation through dot-peek, alas, it work in both cases, and by itself IIncludeableQueryableis inherited from IQueryable 您的问题非常有趣,我首先想到的是类型不匹配,因为我确切地记得FirstAsync带IQueryable的内容,如果我确实包含了某些内容,则请求的类型为IIncludeableQueryable,但是我测试了我的猜测并查看了通过点偷看实现,eek,它在两种情况下均有效,并且IIncludeableQueryable本身继承自IQueryable
var testQuery = DbContext.Practices.Include(x => x.Facility);
var testQuery2 = DbContext.Practices.Select(x => x);
var asyncPracticeCorrectType = await testQuery2.FirstAsync();
var asyncPractice = await testQuery.FirstAsync();
i got entity Practice in both ways:( 我通过两种方式都获得了实体练习:(
I think your problem in area SQLite, because your code look correctly 我认为您在SQLite方面存在问题,因为您的代码看起来正确
I tried entity framework core instead of entity framework 6 which works perfectly according to that problem. 我尝试了实体框架核心,而不是实体框架6,它可以根据该问题完美地工作。
In my option it's a bug in entitiy framework 6 or in the sqlite provider. 在我的选择中,它是entitiy Framework 6或sqlite提供程序中的错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.