【问题标题】:Insert data from server to SQLite Database将数据从服务器插入 SQLite 数据库
【发布时间】:2021-08-09 14:24:04
【问题描述】:

我正在将 3000 多个数据从我的服务器插入到我的 SQLite 数据库中。问题是插入过程非常慢。有没有更好的方法来有效地插入数据?我正在做的是将我从服务器获得的数据转换为 JSON 对象,并一个接一个地插入它。我知道我在做什么是低效的。我该如何解决这个问题?

public class AndroidSQLiteDb : ISQLiteDB
{
    public SQLiteAsyncConnection GetConnection()
    {
        var dbFileName = "backend.db3";
        var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
        var path = Path.Combine(documentsPath, dbFileName);

        return new SQLiteAsyncConnection(path);
    }
}

public async void FirstSyncContacts(string host, string database, string contact)
    {
        try
        {
            var db = DependencyService.Get<ISQLiteDB>();
            var conn = db.GetConnection();

            var sql = "SELECT * FROM tblContacts WHERE Coordinator = '" + contact + "'";
            var getContacts = conn.QueryAsync<ContactsTable>(sql);
            var resultCount = getContacts.Result.Count;
            var current_datetime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:00");

            //Check if the retailer has been sync
            if (resultCount < 1)
            {
                try
                {
                    syncStatus.Text = "Syncing Retailer";

                    var link = Constants.requestUrl + "Host=" + host + "&Database=" + database + "&Contact=" + contact + "&Request=9DpndD";
                    string contentType = "application/json";
                    JObject json = new JObject
                    {
                        { "ContactID", contact }
                    };

                    HttpClient client = new HttpClient();
                    var response = await client.PostAsync(link, new StringContent(json.ToString(), Encoding.UTF8, contentType));

                    if (response.IsSuccessStatusCode)
                    {
                        var content = await response.Content.ReadAsStringAsync();

                        if (content != "")
                        {
                            var contactsresult = JsonConvert.DeserializeObject<List<ContactsData>>(content);

                            foreach (var item in contactsresult)
                            {
                                // update only the properties that you have to...

                                item.LastSync = Convert.ToDateTime(current_datetime);
                                item.ServerUpdate = Convert.ToDateTime(item.ServerUpdate);
                                item.MobileUpdate = Convert.ToDateTime(item.MobileUpdate);
                            }
                            await conn.InsertAsync(contactsresult);

                        }
                    }

                    //Proceed to next function
                    FirstSyncRetailerGroup(host, database, contact);
                }
                catch (Exception ex)
                {
                    Console.Write("Syncing Retailer Error " + ex.Message);
                }
            }
            //If not get the retailer
            else
            {
                SyncContacts(host, database, contact);
            }
        }
        catch (Exception ex)
        {
            Console.Write("Syncing Retailer Error " + ex.Message);
        }
    }

【问题讨论】:

  • 在一个后台线程中使用非异步Insert,而不是3000个单独的异步调用...创建ContactsTable的一个实例并重用(在每个插入循环中重置/设置它的所有属性迭代(将节省大量 GC 时间),无需将所有这些 json 属性(item.XXX)分配给另一个局部变量,只需将它们重新分配给 ContactsTable 的属性即可。
  • @SushiHangover 你能告诉我怎么做吗?
  • @SushiHangover 我真的需要帮助
  • @LawrenceAgulto 请避免在 sqlite 中使用 json。 SQLite 仅用于您的内部目的。因此,您可以在没有 JSON 的情况下进行管理。如果你避免这种情况,你可以看到速度差异
  • @RanjithKumar 我怎样才能避免这种情况?你能告诉我怎么做吗?

标签: xamarin xamarin.forms


【解决方案1】:
  1. 在一个后台线程中使用非异步 Insert,而不是 3000 个单独的异步调用...

  2. 重复使用 DeserializeObject 步骤中的列表,而不是创建将在每次循环迭代时丢弃的新本地对象。

  3. 无需将所有这些 json 属性 (item.XXX) 分配给另一个局部变量,只需根据需要更新每个现有 ContactsData 的属性,然后再将其插入数据库。

使用SQLiteConnection的示例:

// Use the non-async version of SQLiteConnection
var conn = new SQLiteConnection(dbPath, true, null);

// code removed for example...

await System.Threading.Tasks.Task.Run(() =>
{
    var contactsresult = JsonConvert.DeserializeObject<List<ContactsData>>(content);

    // start a transaction block so all 3000 records are committed at once.
    conn.BeginTransaction();

    // Use `foreach` in order shortcut the need to retrieve the object from the list via its index
    foreach (var item in contactsresult)
    {
        // update only the properties that you have to...

        item.LastSync = Convert.ToDateTime(current_datetime);
        item.ServerUpdate = Convert.ToDateTime(item.ServerUpdate);
        item.MobileUpdate = Convert.ToDateTime(item.MobileUpdate);

        conn.Insert(item);
    }
    conn.Commit();
});

使用SQLiteAsyncConnection的示例:

var db = DependencyService.Get<ISQLiteDB>();
var conn = db.GetConnection();

~~~

var contactsresult = JsonConvert.DeserializeObject<List<ContactsData>>(content);

foreach (var item in contactsresult)
{
    // update only the properties that you have to...

    item.LastSync = Convert.ToDateTime(current_datetime);
    item.ServerUpdate = Convert.ToDateTime(item.ServerUpdate);
    item.MobileUpdate = Convert.ToDateTime(item.MobileUpdate);
}
conn.InsertAsync(contactsresult); // Insert the entire list at once...

【讨论】:

  • 我正在使用我的代码将数据从我的服务器同步到我的 sqlite 数据库中,我还能使用 var db = DependencyService.Get(); var conn = db.GetConnection();
  • 依赖服务?是的,只需添加一个返回非异步连接的另一个 Get ......
  • 你能根据我的代码展示你的完整代码吗?我很困惑
  • 我的完整代码?该代码是根据您的代码直接写入 Stackoverflow
  • 我的意思是你能修改这个 var conn = new SQLiteConnection(dbPath, true, null);并使用这个 var db = DependencyService.Get(); var conn = db.GetConnection();
【解决方案2】:

我遇到了同样的问题,所以即使答案晚了几年,也许对某人有用。

我就是这样做的。

首先:我从服务器获取所有数据为 json

var response = await client.GetAsync("your_server_url");
var content = await response.Content.ReadAsStringAsync();
ResponseData = JsonConvert.DeserializeObject<DataModel>(content);

第二:将数据保存到数据库

await conn.InsertAllAsync(ResponseData)

但在我的情况下,因为我们的应用程序使用离线数据,我首先将所有数据插入临时表中,然后我获取所有新记录比较主表和临时表表。

NewDataFromTemp = await conn.QueryAsync<DataModel>("SELECT * FROM [TableTemp] t WHERE t.[TABLE_ID] NOT IN (SELECT g.[TABLE_ID] FROM [MainTable] g)");

在主表中插入新记录

await conn.InsertAllAsync(NewDataFromTemp)

然后我检查更新记录

UpdatedDataFromTemp = await conn.QueryAsync<DataModel>("SELECT t.* FROM [TableTemp] t, [MainTable] o WHERE t.[TABLE_ID]=o.[TABLE_ID] AND t.[TABLE_UPDATED]>o.[TABLE_UPDATED]");

并且更新主表中的所有记录

await conn.UpdateAllAsync(UpdatedDataFromTemp);

我使用逻辑删除,所以更新时逻辑删除也会更新。

【讨论】:

    猜你喜欢
    • 2018-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-24
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    • 2021-12-28
    相关资源
    最近更新 更多