简体   繁体   English

SQLite EF6异步API引发InvalidCastException

[英]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. 为避免出现诸如“您正在同一查询对象上调用FirstFirstAsync ...”的提示:否。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM