Exception:
Local variable/parameter ':your-param-name' can only be used within a database procedure.
In MSSQL, the param character is #. In INGRES Database, really is : ? I cannot find official documentation for that...
SELECT * FROM MyIngresTable WHERE MyColumn = :poorParam
C# with Spring.NET AdoTemplate:
IDbParametersBuilder builder = CreateDbParametersBuilder();
builder.Create().Name("poorParam").Type(DbType.Int32).Value(1);
Any help?
Solved!
Just use INTERROGATION without named param, and pass values in order of usage.
string query = "SELECT * FROM MyIngresTable WHERE MyColumn >= ? and OtherColumn = ?";
IDbParametersBuilder builder = CreateDbParametersBuilder();
builder.Create().Type(DbType.Int32).Value(10);
builder.Create().Type(DbType.String).Size(4).Value("test");
IList<YourModelType> data = AdoTemplate.QueryWithRowMapper(
CommandType.Text,
query,
new YourRowMapper<YourModelType>(),
builder.GetParameters()
);
Another tip about Spring.NET AdoTemplate:
using Spring.Data.Common;
using Spring.Data.Generic;
protected virtual IDbParametersBuilder CreateDbParametersBuilder()
{
return new DbParametersBuilder(AdoTemplate.DbProvider);
}
Thanks also, Panagiotis Kanavos.
Related
I'm facing a problem in PetaPoco, and I can't figure it out.
I'm using this code :
var db = new OracleConnection(_connectionString);
var query = Sql.Builder;
query.Append("SELECT * FROM City WHERE ID = #0", 1);
return db.Query<City>(query.SQL).ToList();
PetaPoco is not adding the parameter to my sql query.
This is an example from their official website :
var id=123;
var sql=PetaPoco.Sql.Builder
.Append("SELECT * FROM articles")
.Append("WHERE article_id=#0", id);
For you information : I'm using the last version of PetaPoco (5.0.1)
I'd skip Sql.Builder (it's gaining you nothing here), and as a side-note, use db.Fetch as it already returns a List. So:
var query = "SELECT * FROM City WHERE ID = #0";
return db.Fetch<City>(query, 1);
Just query to the Query<> method, not just the sql.
Otherwise you need to pass the Arguments as the second parameter.
I am using Entity Framework 4.3, and below is my code (BTW, the RealPrice field of the gift table is of decimal type):
var filters = new StringBuilder();
var parameters = new List<object>();
decimal numRealPrice = 25.00m;
filters.Append("RealPrice = #RealPrice");
var paramRealPrice = new SqlParameter("#RealPrice", SqlDbType.Decimal);
paramRealPrice.Value = numRealPrice;
parameters.Add(numRealPrice);
string sqlStatement = "SELECT * FROM gift WHERE ";
sqlStatement = sqlStatement + filters;
List<OM_Gift_BO> gifts = this.objEntity.ExecuteStoreQuery<OM_Gift_BO>(sqlStatement, parameters.ToArray()).ToList();
//....
And the framework somewhat generated a SQL query(according to Express profiler 2.0):
exec sp_executesql N'SELECT * FROM gift WHERE RealPrice = #RealPrice',N'#p0 decimal(4,2)',#p0=25.00
go
I have no idea where does the name 'p0' come from, however, since it is different from RealPrice, I got an exception saying:
Must declare the scalar variable "#RealPrice".
Well, this method works OK with string type parameters.
Any help is appreciated, thanks in advance.
The problem seems to be your assigning numRealPrice directly to your parameters and passing that directly to ExecuteStoreQuery
Replace
parameters.Add(numRealPrice);
With
parameters.Add(paramRealPrice);
Additionally I'm not sure if its of any value, as it depends on what your trying to achieve, however you could probably shorten your code as follows
var statement = "SELECT * FROM gift WHERE RealPrice = {0}";
var gifts = context.ExecuteStoreQuery<OM_Gift_BO>(statment, numRealPrice).ToList();
I have a very big string to be updated to the memo field of FoxPro Table, I tried
cmd = db.GetSqlStringCommandWrapper("UPDATE xxx SET memo1 = "adfsd" WHERE condition1 = 'satisfied'");
db.ExecuteNonQuery(cmd);
This query overwrites the previous values in the memo1.
I Cannot use MODIFY memo in C#.
How do I append a string to a already existing memo field in Foxpro using C# ?
Try making the command say:
UPDATE xxx SET memo1 = memo1 + "adfsd"
I think the issue is probably with GetSqlStringCommandWrapper which as far as I can see is deprecated.
This shouldn't be a problem to do, for example using the OLEDB provider:
var DBC = #"C:\mydata.dbc";
string ConnectionString = string.Format("Provider=VFPOLEDB.1;Data Source={0};Exclusive=false;Ansi=true;OLE DB Services = 0", DBC);
using (OleDbConnection testConnection = new OleDbConnection(ConnectionString))
{
OleDbCommand updateCommand = new OleDbCommand(#"update mytable set mymemo=alltrim(mymemo)+ttoc(datetime()) where thisfield='THISVALUE'", testConnection);
testConnection.Open();
updateCommand.ExecuteNonQuery();
Console.WriteLine(#"Finished - press ENTER.");
Console.ReadLine();
}
You need to parameterize your query.. Assuming your query wrapper gets the sql connection handle to the database. The VFP OleDB Provider uses "?" as a "place-holder" for parameters and must match the order as associated to your query.
I have a more detailed sample to a very similar question here...
Try something like
string whatToSetItTo = "this is a test string that can even include 'quotes'";
cmd = db.GetSqlStringCommandWrapper("UPDATE YourTable SET memo1 = ? WHERE someKeyColumn = ?");
cmd.Parameters.Add( "parmForMemoField", whatToSetItTo);
cmd.Parameters.Add( "parmForKeyColumn", "satisfied" );
db.ExecuteNonQuery(cmd);
Notice the parameters added in same sequence. whatever the string value is (or could even be integer, date, etc respective to your table structure, but your sample only was based on strings) the place-holders are filled in order. The values would update accordingly.
I'm trying to understand why in C# if you have a sql string why you would have to put tick (') marks in the following where clause in order for this to work. Could someone please explain the reasoning behind this?
where ProgramServer='" + machineName.ToString() + "' and Active=1;
You can avoid those tick (') marks and use Parameters, They will also save you from SQL Injection.
The reason you see those ticks are because SQL expects string type values to be enclosed in single ticks.
What you're seeing is a dynamically built SQL query in the code. When querying based on a string value, the string must be wrapped in single quotes. The final SQL string would look something like:
select * from someTable where ProgramServer = 'YourMachineName' and Active = 1;
Unfortunately, that is far from the best way to do things. You should be using parameterized queries instead:
var query = "select * from someTable where ProgramServer = #machineName and Active = 1;";
using(var conn = new SqlConnection(connString))
{
var command = new SqlCommand(query, conn);
command.Parameters.Add("machineName", machineName.ToString());
// Execute and get the results
}
I have a simple problem with a not so simple solution... I am currently inserting some data into a database like this:
kompenzacijeDataSet.KompenzacijeRow kompenzacija = kompenzacijeDataSet.Kompenzacije.NewKompenzacijeRow();
kompenzacija.Datum = DateTime.Now;
kompenzacija.PodjetjeID = stranka.id;
kompenzacija.Znesek = Decimal.Parse(tbZnesek.Text);
kompenzacijeDataSet.Kompenzacije.Rows.Add(kompenzacija);
kompenzacijeDataSetTableAdapters.KompenzacijeTableAdapter kompTA = new kompenzacijeDataSetTableAdapters.KompenzacijeTableAdapter();
kompTA.Update(this.kompenzacijeDataSet.Kompenzacije);
this.currentKompenzacijaID = LastInsertID(kompTA.Connection);
The last line is important. Why do I supply a connection? Well there is a SQLite function called last_insert_rowid() that you can call and get the last insert ID. Problem is it is bound to a connection and .NET seems to be reopening and closing connections for every dataset operation. I thought getting the connection from a table adapter would change things. But it doesn't.
Would anyone know how to solve this? Maybe where to get a constant connection from? Or maybe something more elegant?
Thank you.
EDIT:
This is also a problem with transactions, I would need the same connection if I would want to use transactions, so that is also a problem...
Using C# (.net 4.0) with SQLite, the SQLiteConnection class has a property LastInsertRowId that equals the Primary Integer Key of the most recently inserted (or updated) element.
The rowID is returned if the table doesn't have a primary integer key (in this case the rowID is column is automatically created).
See https://www.sqlite.org/c3ref/last_insert_rowid.html for more.
As for wrapping multiple commands in a single transaction, any commands entered after the transaction begins and before it is committed are part of one transaction.
long rowID;
using (SQLiteConnection con = new SQLiteConnection([datasource])
{
SQLiteTransaction transaction = null;
transaction = con.BeginTransaction();
... [execute insert statement]
rowID = con.LastInsertRowId;
transaction.Commit()
}
select last_insert_rowid();
And you will need to execute it as a scalar query.
string sql = #"select last_insert_rowid()";
long lastId = (long)command.ExecuteScalar(sql); // Need to type-cast since `ExecuteScalar` returns an object.
last_insert_rowid() is part of the solution. It returns a row number, not the actual ID.
cmd = CNN.CreateCommand();
cmd.CommandText = "SELECT last_insert_rowid()";
object i = cmd.ExecuteScalar();
cmd.CommandText = "SELECT " + ID_Name + " FROM " + TableName + " WHERE rowid=" + i.ToString();
i = cmd.ExecuteScalar();
I'm using Microsoft.Data.Sqlite package and I do not see a LastInsertRowId property. But you don't have to create a second trip to database to get the last id. Instead, combine both sql statements into a single string.
string sql = #"
insert into MyTable values (null, #name);
select last_insert_rowid();";
using (var cmd = conn.CreateCommand()) {
cmd.CommandText = sql;
cmd.Parameters.Add("#name", SqliteType.Text).Value = "John";
int lastId = Convert.ToInt32(cmd.ExecuteScalar());
}
There seems to be answers to both Microsoft's reference and SQLite's reference and that is the reason some people are getting LastInsertRowId property to work and others aren't.
Personally I don't use an PK as it's just an alias for the rowid column. Using the rowid is around twice as fast as one that you create. If I have a TEXT column for a PK I still use rowid and just make the text column unique. (for SQLite 3 only. You need your own for v1 & v2 as vacuum will alter rowid numbers)
That said, the way to get the information from a record in the last insert is the code below. Since the function does a left join to itself I LIMIT it to 1 just for speed, even if you don't there will only be 1 record from the main SELECT statement.
SELECT my_primary_key_column FROM my_table
WHERE rowid in (SELECT last_insert_rowid() LIMIT 1);
The SQLiteConnection object has a property for that, so there is not need for additional query.
After INSERT you just my use LastInsertRowId property of your SQLiteConnection object that was used for INSERT command.
Type of LastInsertRowId property is Int64.
Off course, as you already now, for auto increment to work the primary key on table must be set to be AUTOINCREMENT field, which is another topic.
database = new SQLiteConnection(databasePath);
public int GetLastInsertId()
{
return (int)SQLite3.LastInsertRowid(database.Handle);
}
# How about just running 2x SQL statements together using Execute Scalar?
# Person is a object that has an Id and Name property
var connString = LoadConnectionString(); // get connection string
using (var conn = new SQLiteConnection(connString)) // connect to sqlite
{
// insert new record and get Id of inserted record
var sql = #"INSERT INTO People (Name) VALUES (#Name);
SELECT Id FROM People
ORDER BY Id DESC";
var lastId = conn.ExecuteScalar(sql, person);
}
In EF Core 5 you can get ID in the object itself without using any "last inserted".
For example:
var r = new SomeData() { Name = "New Row", ...};
dbContext.Add(r);
dbContext.SaveChanges();
Console.WriteLine(r.ID);
you would get new ID without thinking of using correct connection or thread-safety etc.
If you're using the Microsoft.Data.Sqlite package, it doesn't include a LastInsertRowId property in the SqliteConnection class, but you can still call the last_insert_rowid function by using the underlying SQLitePCL library. Here's an extension method:
using Microsoft.Data.Sqlite;
using SQLitePCL;
public static long GetLastInsertRowId(this SqliteConnection connection)
{
var handle = connection.Handle ?? throw new NullReferenceException("The connection is not open.");
return raw.sqlite3_last_insert_rowid(handle);
}