不使用SQLitePCL在SQLite中从WCF插入900(大量行)行

时间:2017-12-28 12:22:44

标签: c# sqlite uwp sql-insert

我从WCF获取了大量行,然后我想在我的本地SQLite DB中逐个插入这些行。为此,我正在使用SQLItePCL。使用调试器,我检测到大约有900行,然后我开始一个for循环并逐个插入所有这些行。但它没有插入一行,并且加载器(我使用加载器来显示何时插入数据)加载无限时间。我正在检查LocalState文件夹中我的本地数据库的大小,但它没有增加,这意味着什么也没发生,但我的应用程序也没有崩溃。当行号小于200时,一切都很好。下面是插入数据的代码:

    using (SQLiteConnection Conn = new SQLiteConnection("BerriaDb.db"))
{
    List<BerrianWebService.FoodCode> ResponseData = wsResponse.data.ToList();
    for (int i = 0; i < ResponseData.Count; i++)
    {
        string sqlInsFoodCode = @"INSERT INTO [FoodCode] ([ID], [Item_Name], [Code], [ItemID], [FoodCodeID], [Brief_Descriptor], [Full_Descriptor], [Guidesheet], [REG], [Status], [syncDate]) VALUES (" + ResponseData[i].ID + ", '" + ResponseData[i].Item_Name + "', '" + ResponseData[i].Code + "', '" + ResponseData[i].ItemID + "', '" + ResponseData[i].FoodCodeID + "', '" + ResponseData[i].Brief_Descriptor + "', '" + ResponseData[i].Full_Descriptor + "', '" + ResponseData[i].Guidesheet + "', '" + ResponseData[i].REG + "', '" + ResponseData[i].Status + "', '" + LastSyncDateTime + "')";
        using (ISQLiteStatement connStatement = Conn.Prepare(sqlInsFoodCode))
        {
            connStatement.Step();
        }
    }
}

这可能是什么问题?我应该在这里使用StringBuilder吗?有什么建议吗?感谢

编辑:我注意到主要的问题在于插入命令实际上,当ResponseData太大(如900)时,它无法在每个内部循环并评估其值,它会卡住构建sql字符串,但是当我给出静态值时它工作正常。有什么帮助吗?

1 个答案:

答案 0 :(得分:0)

您的代码对SQL注入攻击是开放的,这也可能解释了为什么构建SQL语句和后续步骤调用失败。

通过引入Bind参数和相应的Prepared statement调用,充分利用Bind。调整您的代码如下:

var LastSyncDateTime = DateTime.Now;

using (SQLitePCL.SQLiteConnection Conn = new SQLitePCL.SQLiteConnection("BerriaDb.db"))
{

    // use Bind Parameters, that are the @id, @item_name etc
    string sqlInsFoodCode = @"
    INSERT INTO [FoodCode] (
        [ID], 
        [Item_Name], 
        [Code], 
        [ItemID], 
        [FoodCodeID], 
        [Brief_Descriptor], 
        [Full_Descriptor], 
        [Guidesheet], 
        [REG], 
        [Status], 
        [syncDate]) 
    VALUES (
        @id, 
        @item_name, 
        @code, 
        @itemid, 
        @foodcodeid, 
        @brief_descriptor, 
        @full_descriptor, 
        @guidesheet, 
        @reg, 
        @status, 
        @lastsynctime)";

    // we can now re use this statement for all inserts
    using (ISQLiteStatement connStatement = Conn.Prepare(sqlInsFoodCode))
    {
        List<FoodCode> ResponseData = wsResponse.data.ToList();
        for (int i = 0; i < ResponseData.Count; i++)
        {
            // just to be sure no values from last time are kept
            connStatement.ClearBindings();

            // bind the values from the Responsedata to the parameters
            connStatement.Bind("@id", ResponseData[i].ID);
            connStatement.Bind("@item_name", ResponseData[i].Item_Name);
            connStatement.Bind("@code", ResponseData[i].Code);
            connStatement.Bind("@itemid", ResponseData[i].ItemID);
            connStatement.Bind("@foodcodeid", ResponseData[i].FoodCodeID);
            connStatement.Bind("@brief_descriptor", ResponseData[i].Brief_Descriptor);
            connStatement.Bind("@full_descriptor", ResponseData[i].Full_Descriptor);
            connStatement.Bind("@guidesheet", ResponseData[i].Guidesheet);
            connStatement.Bind("@reg", ResponseData[i].REG);
            connStatement.Bind("@status", ResponseData[i].Status);
            connStatement.Bind("@lastsynctime", LastSyncDateTime.ToString());

            // alwaws take the result ...
            var result = connStatement.Step();
            // ... and check if we're OK, (done in this case)
            if (result != SQLiteResult.DONE) 
            {
                // if not, yell at the caller
                throw new Exception(String.Format("ResponseData[{0}].ID('{1}') not inserted. Result: {2}", i, ResponseData[i].ID, result));   
            }
            // enable the re-use of the prepared statement, so call Reset
            connStatement.Reset();               
        }
    }
}

在10秒钟内插入100行,这个时间是线性的。

在测试期间,您可能希望使用":memory:"作为数据库名称。这将为您提供一个内存存储,比在磁盘上写入快得多。

如果有人想给这个测试人员,这里有支持类:

// this will be an instance in wsResponse
class response
{   public response() {
      data = Enumerable.Range(1,10).Select(id => new FoodCode(id)).ToArray();
   }
   public FoodCode[] data;
}

class FoodCode
{
    public int ID;
    public string Item_Name;
    public string Code;
    public int ItemID;
    public int FoodCodeID;
    public string Brief_Descriptor;
    public string Full_Descriptor;
    public string Guidesheet;
    public string REG;
    public string Status;

    public FoodCode()
    {
        // populate all fields with random stuff
        foreach(FieldInfo fi in this.GetType().GetFields())
        {
            if (fi.FieldType == typeof(string)) {
                fi.SetValue(this, GenString(fi.Name, ID));
            } else
            {
                fi.SetValue(this, rnd.Next(1,255));
            }
        }
    }

    public FoodCode(int id):this()
    {
        ID = id;
    }

    static Random rnd = new Random();
    // generate a random string
    private string GenString(string name, int id)
    { 
    var result = new string[] { name, id.ToString(), new String(Enumerable.Range(0,5000).Select(_=> (char) rnd.Next(33,127)).ToArray())};
    return String.Join("-", result);
    }

}