I developed code to get the Json sent from my rest service.
I receive and threat the code and generate the sql insert statement.
I got this error:
[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
My Bulk Insert Method
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);
}
}
My utils methods
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();
}
And my ViewModel class
This is the method who I call when start to syncronize
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);
}
}
And this is method where the error happens
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);
}
}
I received paginated date because there are 8500 registers, sometimes don´t happen the error, but in the other, I don´t uderstant the erro.
And my model class
[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; }
}
I sent almost the time the Id, when has
My API not throw exception.
The SQLite.SQLiteException: Constraint exception and the fact that it's randomly occurring is key. You are violating a table constraint somewhere.
Your SQLite table is expecting a value that it's not receiving. For example, if one of your data fields is marked "NOT NULL" in the table and a field in your data is NULL, that constraint will fail and you will receive the exception.
You need to determine which fields have constraints and then handle the received data to ensure constraint integrity. Convert null TEXT values to String.Empty or null INTEGER fields from null to 0 if the table has a NOT NULL constraint. You will have to look at the set constraints in the data structure.
With that said you should really look into parameterized queries. Your current INSERT statement is just asking for trouble as it's vulnerable to injection. For example, if one of the value strings contains a comma, it can break your statement because SQLite doesn't know value is just a value and just treats it as part of the query commands. Parameters fix this. This could also, be what is causing your issue if you are correctly following your table constaints.
Here's a small example of how your queries should be built instead using parameters.
cmd.CommandText = "INSERT INTO MyTable (CompanyName, Address) VALUES (#Name, #Address)";
cmd.Parameters.AddWithValue("#CompanyName", myCompanyNameString);
cmd.Parameters.AddWithValue("#Address", myAddressString);
Since my dynamic query values are parameterized, I can make my values have special characters or statements like "DROP TABLE" and it will be handled correctly and protect from injection attack or exceptions from query breaking characters or words.
Related
I am trying to insert data into one of my database tables using the Dapper orm but i can't seem to get it right using the ExecuteAsync method.
When i am using the ExecuteScalarAsync method, everything seems to be working as intended :
RequestEvent ev = new();
ev.Title = string.Empty;
ev.Description = string.Empty;
ev.NewValue = string.Empty;
ev.MemberId = 1;
ev.RequestId = 1;
long requestEventInsertedId = await context.Connection.ExecuteScalarAsync<long>(#"
INSERT INTO RequestEvent (Title, Description, MemberId, RequestId, NewValue)
VALUES (#Title, #Description, #MemberId, #RequestId, #NewValue)
RETURNING Id", ev);
// it works, requestEventInsertedId's value is the inserted autoincremented id
I am trying to use ExecuteAsync with a similar approach without success :
RequestEvent ev = new();
ev.Title = string.Empty;
ev.Description = string.Empty;
ev.NewValue = string.Empty;
ev.MemberId = 1;
ev.RequestId = 1;
await context.Connection.ExecuteAsync(#"
INSERT INTO RequestEvent (Title, Description, MemberId, RequestId, NewValue)
VALUES (#Title, #Description, #MemberId, #RequestId, #NewValue)", ev);
Executing this code throws the following Exception Without further explanations :
Microsoft.Data.Sqlite.SqliteException : 'SQLite Error 19: 'FOREIGN KEY constraint failed'.'
MemberId and RequestId properties are foreign keys but are obviously provided with this code.
Why do i have this error using the ExecuteAsync method ?
RequestEvent model :
public class RequestEvent
{
public long Id { get; set; }
public DateTime DateTime { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string NewValue { get; set; }
public long MemberId { get; set; }
public long RequestId { get; set; }
}
RequestEvent table schema from my migration (I am using FluentMigrator)
Create.Table("RequestEvent")
.WithColumn("Id").AsInt64().PrimaryKey().NotNullable().Identity()
.WithColumn("DateTime").AsDateTime().WithDefaultValue(SystemMethods.CurrentDateTime)
.WithColumn("Title").AsString().Nullable()
.WithColumn("Description").AsString().Nullable()
.WithColumn("NewValue").AsString().Nullable()
.WithColumn("MemberId").AsInt64().Nullable().ForeignKey("Member", "Id").OnDeleteOrUpdate(Rule.SetNull)
.WithColumn("RequestId").AsInt64().Nullable().ForeignKey("Request", "Id").OnDeleteOrUpdate(Rule.SetNull);
I am cassandra for custom logging my .netcore project, i am using CassandraCSharpDriver.
Problem:
I have created UDT for params in log, and added list of paramUDT in Log table as frozen.
But i am getting error: Non-frozen UDTs are not allowed inside collections. I don't know why ia m getting this error because i am using Frozen attribute on list i am using in Log Model.
logSession.Execute($"CREATE TYPE IF NOT EXISTS {options.Keyspaces.Log}.{nameof(LogParamsCUDT)} (Key text, ValueString text);");
Here is model:
public class Log
{
public int LoggingLevel { get; set; }
public Guid UserId { get; set; }
public string TimeZone { get; set; }
public string Text { get; set; }
[Frozen]
public IEnumerable<LogParamsCUDT> LogParams { get; set; }
}
Question where i am doing wrong, is my UDT script not correct or need to change in model.
Thanks in advance
I've tried using that model and Table.CreateIfNotExists ran successfully.
Here is the the code:
public class Program
{
public static void Main()
{
var cluster = Cluster.Builder().AddContactPoint("127.0.0.1").Build();
var session = cluster.Connect();
session.CreateKeyspaceIfNotExists("testks");
session.ChangeKeyspace("testks");
session.Execute($"CREATE TYPE IF NOT EXISTS testks.{nameof(LogParamsCUDT)} (Key text, ValueString text);");
session.UserDefinedTypes.Define(UdtMap.For<LogParamsCUDT>($"{nameof(LogParamsCUDT)}", "testks"));
var table = new Table<Log>(session);
table.CreateIfNotExists();
table.Insert(new Log
{
LoggingLevel = 1,
UserId = Guid.NewGuid(),
TimeZone = "123",
Text = "123",
LogParams = new List<LogParamsCUDT>
{
new LogParamsCUDT
{
Key = "123",
ValueString = "321"
}
}
}).Execute();
var result = table.First(l => l.Text == "123").Execute();
Console.WriteLine(JsonConvert.SerializeObject(result));
Console.ReadLine();
table.Where(l => l.Text == "123").Delete().Execute();
}
}
public class Log
{
public int LoggingLevel { get; set; }
public Guid UserId { get; set; }
public string TimeZone { get; set; }
[Cassandra.Mapping.Attributes.PartitionKey]
public string Text { get; set; }
[Frozen]
public IEnumerable<LogParamsCUDT> LogParams { get; set; }
}
public class LogParamsCUDT
{
public string Key { get; set; }
public string ValueString { get; set; }
}
Note that I had to add the PartitionKey attribute or else it wouldn't run.
Here is the CQL statement that it generated:
CREATE TABLE Log (
LoggingLevel int,
UserId uuid,
TimeZone text,
Text text,
LogParams frozen<list<"testks"."logparamscudt">>,
PRIMARY KEY (Text)
)
If I remove the Frozen attribute, then this error occurs: Cassandra.InvalidQueryException: 'Non-frozen collections are not allowed inside collections: list<testks.logparamscudt>'.
If your intention is to have a column like this LogParams frozen<list<"testks"."logparamscudt">> then the Frozen attribute will work. If instead you want only the UDT to be frozen, i.e., LogParams list<frozen<"testks"."logparamscudt">>, then AFAIK the Frozen attribute won't work and you can't rely on the driver to generate the CREATE statement for you.
All my testing was done against cassandra 3.0.18 using the latest C# driver (3.10.1).
I'm trying to pull data from an Access database using dapper. I have the following class defined to use the fields from the access database that I need to read. I then tried to pull the data using the code below. When I run this only blanks come back. The number of blanks match the number of records in the data table.
I tried to use a shorter sql string with the same results.
I can't find any information on this issue, does anyone have any ideas about this?
public class DLabResults
{
public int ResultsFolderNumber { get; set; }
public int Request { get; set; }
public int Release { get; set; }
public string Formulation { get; set; }
public string Container { get; set; }
public string Closure { get; set; }
public string Shipper { get; set; }
// public string Label_Back { get; set; }
// public string Label_Front { get; set; }
public string FilePath { get; set; }
}
public void LoadDapperDLabResults(List<DLabResults> items)
{
string sql = "";
//sql = "SELECT tblResults_Results.R_Project_Assignment, tblResults_Results.R_Project_Request, tblResults_Results.R_Project_Release, tblResults_Results.R_Formulation, tblResults_Results.R_Closure, tblResults_Results.R_Container, tblResults_Results.R_Shipper, '' AS Blank1, '' AS Blank2, tblResults_Results.R_Test_FullPath FROM tblResults_Results WHERE(((tblResults_Results.R_Formulation)Like '*' & [Formulation] & '*') AND ((tblResults_Results.R_Closure)Like '*' & [Closure] & '*') AND((tblResults_Results.R_Container)Like '*' & [Container] & '*') AND((tblResults_Results.R_Shipper)Like '*' & [Shipper] & '*')) ORDER BY tblResults_Results.R_Project_Assignment, tblResults_Results.R_Project_Request, tblResults_Results.R_Project_Release;";
sql = "SELECT * FROM tblResults_Results";
using (OleDbConnection connection = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Users\\DavidsoJ\\Desktop\\Fixed Push Workbooks\\Redesigned Databases\\Development Lab Results Database.accdb"))
{
//var TM2 = connection.Query<DLabResults>(sql).ToList();
List<DLabResults> TM2 = connection.Query<DLabResults>(sql).ToList();
//add items to employess
if (items == null || items.Count < 1)
{
}
else
{
TM2.AddRange(items);
}
dataGridView1.DataSource = TM2;
}
}
The column names from the SQL query do not seem to match up with the properties of the desired object model DLabResults.
Either update the columns names returned from the query to match the object
SELECT tblResults_Results.R_Project_Request AS Request
/*, ... code removed for brevity */
FROM tblResults_Results
OR update the DLabResults property names to match the column names returned from the query
public class DLabResults {
public int R_Project_Request{ get; set; }
//... code removed for brevity
}
Either way, when using dapper the column names need to be mapped to object members in order for dapper to populate them.
I have a table called Activity (Mobile service), and i add a query in reading:
Azure Script:
function read(query, user, request)
{
var param = request.parameters.UserLocation;
if(param)
{
var sql = "Select TOP 10 [NewsItemUrl], count(1) as CounterNews FROM [MobileServiceExtra].[ACTIVITY] WHERE [UserLocation] = ? GROUP BY [NewsItemUrl] ORDER BY CounterNews Desc";
mssql.query(sql,param, {success: function(results) {request.respond(statusCodes.OK, results);}});
}
//request.execute();
}
Client side:
public class ACTIVITY
{
public int Id { get; set; }
[JsonProperty(PropertyName = "UserLocation")]
public string _UserLocation { get; set; }
[JsonProperty(PropertyName = "NewsItemUrl")]
public string _NewsItemUrl { get; set; }
[JsonProperty(PropertyName = "NewsItemTitle")]
public string _NewsItemTitle { get; set; }
[JsonProperty(PropertyName = "NewsItemPublisher")]
public string _NewsItemPublisher { get; set; }
}
If I do the query in sql, I get 2 columns CounterNews and NewsItemUrl and where the Last is the number of times to repeat the url. However, I dont know how to get the data in column "CounterNews", i mean, when i want to get the query, i get to do with the Activity table (class) and obviously returns me the data correctly, but only NewsItemUrl column and the other fields are empty.
Client side:
private MobileServiceCollection<ACTIVITY, ACTIVITY> TopReadCollectionActivity;
private IMobileServiceTable<ACTIVITY> ACTIVITYTable = App.MobileService.GetTable<ACTIVITY>();
private async void LoadTop10()
{
var dict = new Dictionary<string, string>
{
{ "UserLocation", "United States" },
};
try
{
TopReadCollectionActivity = await ACTIVITYTable.WithParameters(dict).ToCollectionAsync();
}
catch (Exception ex)
{
string err = ex.Message;
}
}
if i create a class (table too)"Top10", azure give a error, because the table doen't exist. and
not want to create a new table.
how to get the query only two fields CounterNews and NewsItemUrl?
Perhaps you should just query the table directly using the OData support. This way your not confined to the structure of your table. Take a look at this for reference.
http://msdn.microsoft.com/en-us/library/windowsazure/jj677199.aspx
I have a company that contains an address object. The SQL return is flat, and I'm tring to get Query<> to load all the objects.
cnn.Query<Company,Mailing,Physical,Company>("Sproc",
(org,mail,phy) =>
{
org.Mailing = mail;
org.Physical = phy;
return org;
},
new { ListOfPartyId = stringList }, null, true, commandTimeout: null,
commandType: CommandType.StoredProcedure, splitOn: "MailingId,PhyscialId").ToList();
I'm not sure if i have the SplitOn correct either. I'm getting the message:
When using the multi-mapping APIs ensure you set the splitOn param if
you have keys other than Id Parameter name: splitOn
Suggestions would be great.
The examples in the Test.cs are not what the code asks for as parameters for the queries. These need to be updated
for me this works perfect ... perhaps a typo?
I see PhyscialId which definitely looks like one.
class Company
{
public int Id { get; set; }
public string Name { get; set; }
public Mailing Mailing { get; set; }
public Physical Physical { get; set; }
}
class Mailing
{
public int MailingId { get; set; }
public string Name { get; set; }
}
class Physical
{
public int PhysicalId { get; set; }
public string Name { get; set; }
}
public void TestSOQuestion()
{
string sql = #"select 1 as Id, 'hi' as Name, 1 as MailingId,
'bob' as Name, 2 as PhysicalId, 'bill' as Name";
var item = connection.Query<Company, Mailing, Physical, Company>(sql,
(org, mail, phy) =>
{
org.Mailing = mail;
org.Physical = phy;
return org;
},
splitOn: "MailingId,PhysicalId").First();
item.Mailing.Name.IsEqualTo("bob");
item.Physical.Name.IsEqualTo("bill");
}