C# SQLite异步任务和等待操作符-任务是否按正确的顺序执行?

C# SQLite异步任务和等待操作符-任务是否按正确的顺序执行?,c#,xamarin,async-await,task,sqlite-net,C#,Xamarin,Async Await,Task,Sqlite Net,我有一个包含多个表的SQLiteAsyncConnection数据库,我想在插入其中一个表后获取主键。我的插入在数据库模型中看起来像这样 public Task SaveZoneAsync(Zone zone) { if (zone.ID == 0) { return database.InsertAsync(zone); } else { return

我有一个包含多个表的SQLiteAsyncConnection数据库,我想在插入其中一个表后获取主键。我的插入在数据库模型中看起来像这样

    public Task SaveZoneAsync(Zone zone)
    {
        if (zone.ID == 0)
        {
            return database.InsertAsync(zone);
        }
        else
        {
            return database.UpdateAsync(zone);
        }
    }
在数据库模型中,我还有一个从给定表中获取最后一个插入id的方法

    public async Task<int> GetLastInsertAsync(String tablename)
    {
        int x = await database.ExecuteScalarAsync<int>("SELECT last_insert_rowid() FROM " + tablename);
        return x;
    }

我的问题是
AddZoneToDB
方法中的
AddZone.Wait()
是否会确保
AddZone
任务在从
getID.Result
获取int之前完成运行?基本上是为了确保我总是从正确的记录中获得正确的ID。我只是不确定
Wait()
RunSynchronously()
如何协同工作。这是Xamarin.Forms中的Xamarin SQLite数据库。ID被设置为主键,并在区域模型中自动递增。

避免使用
任务.工厂.开始新建
,而是使用
任务.运行
。但是,由于目标成员已经返回了一个
任务
,因此实际上不需要
任务。运行

尝试使代码始终异步,而不是尝试混合异步和阻塞代码

public static async Task<int> AddZoneToDbAsync(Zone zone) {
    await App.Database.SaveZoneAsync(zone);
    int zoneID = await App.Database.GetLastInsertAsync("Zone");
    return zoneID;
}

参考

避免使用
Task.Factory.StartNew
,而是使用
Task.Run
。但是,由于目标成员已经返回了一个
任务
,因此实际上不需要
任务。运行

尝试使代码始终异步,而不是尝试混合异步和阻塞代码

public static async Task<int> AddZoneToDbAsync(Zone zone) {
    await App.Database.SaveZoneAsync(zone);
    int zoneID = await App.Database.GetLastInsertAsync("Zone");
    return zoneID;
}

参考资料这里有两个问题。

您要问的问题是:在这种情况下,我应该如何正确使用async Wait。还有一个,你没有提到的:你添加/更新了一个元素,并要求最后一个插入区域的ID

您是否绝对确定,在添加/更新和查询最后插入的ID之间,可能没有其他进程添加了区域?您是想要刚才添加/更新的区域Id,还是想要其他进程添加的区域Id

为了确保获得刚才添加/更新的项目的Id,明智的做法是让
database.InsertAsync
database.UpdateAsync
返回完整的添加/更新区域(就像实体框架一样),或者至少返回添加/更新区域的Id

这些函数应该类似于:

async Task<int> InsertAsync(Zone zone)
{
     .. // async do the insert; await until done
     int zoneId = ... // get the Id of the inserted Zone
     return zoneId;
}
异步任务插入同步(区域)
{
../async执行插入;等待直到完成
int zoneId=…//获取插入区域的Id
返回区ID;
}
如果您可以保证在插入区域和获取插入区域的Id之间没有其他人可以干预,那么就可以保证您获得正确的Id

回到您关于异步等待的问题

Async Await通常用于线程必须等待另一个进程完成某些操作时:写入文件、从数据库检索数据、从internet获取信息。你的线程可以做其他有用的事情,而不是等待

与厨师做早餐相比。在中间搜索某处等待。把茶壶里的水烧开后。他不会无所事事地等待。相反,他开始切西红柿。当水沸腾时,他继续泡茶

如果你的线程没有其他事情要做,那么开始一个新线程做事情是没有用的。这方面的开销将减慢进程。我的建议是让线程使用async Wait完成所有事情。只有当你的线程必须做冗长的计算,而你的线程可以做其他有用的事情时,让另一个线程做冗长的计算才是有用的。但是如果你的线程除了等待这个冗长计算的结果之外没有其他事情要做,那就让你的线程来做吧

因此,我的建议如下。使用上述调整后的InsertAsync:

// Inserts / Updates Zone; returns the ID of the Saved zone
public async Task<int> SaveZoneAsync(Zone zone)
{
    if (zone.ID == 0)
    {
        int zoneId = await database.InsertAsync(zone);
        return zoneId;
    }
    else
    {
        await database.UpdateAsync(zone);
        return zone.Id;
    }
}

public static int AddZoneToDB(Zone zone)
{
    Task<int> taskSaveZone = Task.Run( () => SaveZoneAsync(zone);
    taskSaveZone.Wait();
    int zoneId = taskSaveZone.Result;
    return zoneId;

    // TODO: consider putting this all in one statement
}
//插入/更新区域;返回已保存区域的ID
公共异步任务SaveZoneAsync(区域)
{
如果(zone.ID==0)
{
int zoneId=wait database.InsertAsync(区域);
返回区ID;
}
其他的
{
wait database.UpdateAsync(区域);
返回区.Id;
}
}
公共静态int AddZoneToDB(区域)
{
Task taskSaveZone=Task.Run(()=>SaveZoneAsync(zone);
taskSaveZone.Wait();
int zoneId=taskSaveZone.Result;
返回区ID;
/todo:考虑把这一切放在一个语句中
}

这里有两个问题。

您要求的一个:在这种情况下,我应该如何正确使用async Wait。另一个,您没有提到的一个:添加/更新一个元素,并要求提供上次插入区域的ID

您是否绝对确定在添加/更新和查询最后一个插入的ID之间,没有其他进程添加了区域?您是想要刚才添加/更新的区域的ID,还是想要其他进程添加的区域的ID

为了确保获得刚才添加/更新的项目的Id,明智的做法是让
database.InsertAsync
database.UpdateAsync
返回完整的添加/更新区域(就像实体框架一样),或者至少返回添加/更新区域的Id

这些函数应该类似于:

async Task<int> InsertAsync(Zone zone)
{
     .. // async do the insert; await until done
     int zoneId = ... // get the Id of the inserted Zone
     return zoneId;
}
异步任务插入同步(区域)
{
../async执行插入;等待直到完成
int zoneId=…//获取插入区域的Id
返回区ID;
}
如果您可以保证在插入区域和获取插入区域的Id之间没有其他人可以干预,那么就可以保证您获得正确的Id

回到您关于异步等待的问题

Async Await通常在线程必须等待另一个进程完成某项任务时使用:写入文件、检索数据
// Inserts / Updates Zone; returns the ID of the Saved zone
public async Task<int> SaveZoneAsync(Zone zone)
{
    if (zone.ID == 0)
    {
        int zoneId = await database.InsertAsync(zone);
        return zoneId;
    }
    else
    {
        await database.UpdateAsync(zone);
        return zone.Id;
    }
}

public static int AddZoneToDB(Zone zone)
{
    Task<int> taskSaveZone = Task.Run( () => SaveZoneAsync(zone);
    taskSaveZone.Wait();
    int zoneId = taskSaveZone.Result;
    return zoneId;

    // TODO: consider putting this all in one statement
}