【问题标题】:Exception when trying to make bulk insert in xamarin app with sqlite尝试使用 sqlite 在 xamarin 应用程序中进行批量插入时出现异常
【发布时间】:2020-03-13 03:20:16
【问题描述】:

我开发了代码来获取从我的休息服务发送的 Json。

我收到并威胁代码并生成 sql 插入语句。

我收到了这个错误:

[0:] SQLite.SQLiteException: Constraint
  at SQLite.SQLiteCommand.ExecuteNonQuery () [0x000ca] in <84b9c9e630fa45bd8ac799333976ebbf>:0 
  at GSAN_Mobile.Repository.GsanMobileRepository`1+<>c__DisplayClass9_1[T].<BulkInsert>b__0 (Newtonsoft.Json.Linq.JToken register) [0x0002c] in D:\Projetos\Gsan\mobile\front\GSAN_Mobile\GSAN_Mobile\GSAN_Mobile\Repository\GsanMobileRepository.cs:185 
  at System.Collections.Generic.List`1[T].ForEach (System.Action`1[T] action) [0x0001e] in <6de48997d0c0445dbea8d4d83492d8c6>:0 
  at GSAN_Mobile.Repository.GsanMobileRepository`1[T].BulkInsert (Newtonsoft.Json.Linq.JArray array, System.String tableName) [0x00062] in D:\Projetos\Gsan\mobile\front\GSAN_Mobile\GSAN_Mobile\GSAN_Mobile\Repository\GsanMobileRepository.cs:180 

我的批量插入方法

public void BulkInsert(JArray array, string tableName = "")
{
    try
    {
        if (string.IsNullOrEmpty(tableName))
        {
            Type typeParameterType = typeof(T);
            tableName = typeParameterType.Name;
        }

        using (SQLiteConnection connection = new SQLiteConnection(DataBaseUtil.GetDataBasePath()))
        {
            connection.BeginTransaction();

            array.ToList().ForEach(register =>
            {
                string sql = DataBaseUtil.GenerateInsertStatement(register, tableName);
                System.Diagnostics.Debug.WriteLine(sql);
                var command = connection.CreateCommand(sql);
                command.ExecuteNonQuery();
            });

            connection.Commit();
            DataBaseUtil.CloseConnection(connection);
        }
    }
    catch (Exception e)
    {
        LogUtil.WriteLog(e);
    }
}

我的实用方法

public static string GenerateInsertStatement(JToken register, string tableName)
{
    var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(register.ToString());
    string columns = string.Join(",", data.Keys.ToList());
    string values = string.Join(",", data.Values.Select(v => string.Format(@"'{0}'", v.Trim())));
    return string.Format("INSERT INTO {0} ({1}) VALUES ({2}); ", tableName, columns, values);
}

public static void CloseConnection(SQLiteConnection connection)
{
    connection.Dispose();
    connection.Close();
}

还有我的 ViewModel 类

这是我开始同步时调用的方法

private async Task RegistrarDados()
{
    try
    {
        _logs.Add("Realizando o Download: ");

        GenerateAtendimentoMotivosEncerramento();
        GenerateHidrometrosLocalInstalacao();
        GenerateHidrometrosProtecao();
        GenerateFuncionarios();
        GenerateGrupoFaturamento();
        GenerateLigacaoAguaSituacoes();
        GenerateLigacaoEsgotoSituacoes();
        GenerateServicosTipo();
        GenerateSistemParametros();
        GenerateOrdensServico();
        //GenerateContas();

        int contador = _ordemServicoRepository.Count<OrdemServico>();

        _logs.Add("Sincronização encerrada com sucesso!");
        await App.Current.MainPage.DisplayAlert("Atenção", "Foram importados " + contador + " Ordens de Serviços!", "OK");
        PodeSincronizar = true;
    }
    catch (Exception e)
    {
        LogUtil.WriteLog(e);
    }
}

这是发生错误的方法

private async void GenerateOrdensServico()
{
    try
    {
        _logs.Add("ORDENS DE SERVIÇO");

        int? records = await _ordemServicoRest.GetCount();
        int? limit = _sistemaParametroRepository.GetTamanhoPaginaSincMobile();
        int? pages = (records / limit);

        for (int i = 0; i <= pages; i++)
        {
            JArray ordensServico = await _ordemServicoRest.GetAllInJsonFormatPaginated(DataBaseUtil.GetPagination(i, limit.Value));

            if (ordensServico == null)
            {
                _logs.Add("Não Contem O.S de Corte para importar!");
                await App.Current.MainPage.DisplayAlert("Atenção", "Não tem O.S para importar!", "OK");
                continue;
            }

            _ordemServicoRepository.BulkInsert(ordensServico);
        }
    }
    catch (Exception e)
    {
        LogUtil.WriteLog(e);
    }
}

我收到分页日期是因为有 8500 个寄存器,有时不会发生错误,但另一方面,我不了解错误。

还有我的模型课

[Serializable]
public class Persistent
{
    [AutoIncrement]
    [PrimaryKey]
    [NotNull]
    [JsonProperty("id")]
    public int? Id { get; set; }
}

[Table("OrdemServico")]
public class OrdemServico : Persistent
{

    [JsonProperty("situacaoOS")]
    public int? SituacaoOS { get; set; }

    [JsonProperty("idServicoTipo")]
    public int? IdServicoTipo { get; set; }

    [JsonProperty("dataGeracao")]
    public string DataGeracao { get; set; }

    [JsonProperty("idRegistroAtendimento")]
    public int? IdRegistroAtendimento { get; set; }

    [JsonProperty("idgrupo")]
    public int? IdGrupo { get; set; }

    [JsonProperty("matriculaCliente")]
    public int? MatriculaCliente { get; set; }

    [JsonProperty("nomeCliente")]
    public string NomeCliente { get; set; }

    [JsonProperty("tipoLogradouro")]
    public string TipoLogradouro { get; set; }

    [JsonProperty("logradouro")]
    public string Logradouro { get; set; }

    [JsonProperty("numeroImovel")]
    public int? NumeroImovel { get; set; }

    [JsonProperty("numeroCep")]
    public int? NumeroCep { get; set; }

    [JsonProperty("bairro")]
    public string Bairro { get; set; }

    [JsonProperty("numeroHidrometro")]
    public string NumeroHidrometro { get; set; }

    [JsonProperty("idHidrometroProtecao")]
    public int? IdHidrometroProtecao { get; set; }

    [JsonProperty("idHidrometroLocalInstalacao")]
    public int? IdHidrometroLocalInstalacao { get; set; }

    [JsonProperty("imovel")]
    public int? Imovel { get; set; }

    [JsonProperty("ligacaoAguaSituacao")]
    public int? LigacaoAguaSituacao { get; set; }

    [JsonProperty("ligacaoEsgotoSituacao")]
    public int? LigacaoEsgotoSituacao { get; set; }

    [JsonProperty("sincronizada")]
    public int? Sincronizada { get; set; }
}

我几乎发送了 Id 的时间,什么时候有 我的 API 没有抛出异常。

【问题讨论】:

    标签: c# sqlite xamarin sqlite-net


    【解决方案1】:

    SQLite.SQLiteException: Constraint 异常及其随机发生的事实是关键。您在某处违反了表约束。

    您的 SQLite 表需要一个它没有收到的值。例如,如果您的某个数据字段在表中标记为“NOT NULL”,并且您的数据中的某个字段为 NULL,则该约束将失败并且您将收到异常。

    您需要确定哪些字段有约束,然后处理接收到的数据以确保约束完整性。如果表具有NOT NULL 约束,则将空TEXT 值转换为String.Emptynull INTEGER 字段从null 到0。您将不得不查看数据结构中的设置约束。

    话虽如此,您应该真正研究参数化查询。您当前的INSERT 声明只是在自找麻烦,因为它很容易被注入。例如,如果 value 字符串之一包含逗号,它可能会破坏您的语句,因为 SQLite 不知道 value 只是一个值,只是将其视为查询命令的一部分。参数解决了这个问题。如果您正确遵循表格内容,这也可能是导致您出现问题的原因。

    下面是一个小例子,说明应该如何使用参数构建查询。

    cmd.CommandText = "INSERT INTO MyTable (CompanyName, Address) VALUES (@Name, @Address)";
    cmd.Parameters.AddWithValue("@CompanyName", myCompanyNameString);
    cmd.Parameters.AddWithValue("@Address", myAddressString);
    

    由于我的动态查询值是参数化的,我可以使我的值具有特殊字符或诸如“DROP TABLE”之类的语句,它将被正确处理并防止注入攻击或查询中断字符或单词的异常。

    【讨论】:

    • 我不知道为什么但是我的sqlite没有Parameters方法
    • 你在使用System.Data.SQLite吗?如果是这样,它应该在SqliteCommand 对象中可用。如果它不存在那就奇怪了。
    • 我正在为 Xamarin 使用 SQLiteNetExtensionssqlite-net-pcl
    • 您可以改用cmd.Bind("@CompanyName", myCompanyNameString)
    猜你喜欢
    • 2013-10-10
    • 2013-11-16
    • 2019-09-18
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多