CompositeId and Identity_Insert - sql-server

I have a class mapped like the following:
public class FooMap : ClassMap<Foo>
{
public FooMap()
{
Table("Foo");
LazyLoad();
CompositeId().KeyProperty(x => x.ID,
kp => kp.ColumnName("Id")
.Type(typeof(long)))
.KeyProperty(x => x.ValidFrom);
}
}
On the MSSQL side, Id is identity column and the table's PK is composed of Id and ValidFrom.
Here's the code I use to save:
ISession session = SessionService.GetSession();
new SqlCommand("SET IDENTITY_INSERT Foo ON",
session.Connection as SqlConnection)
.ExecuteNonQuery();
try
{
// performs various versioning checks,
// then saves using transaction.
// The session is the same as above
GenericDataService.Save(myFoo);
}
finally
{
new SqlCommand("SET IDENTITY_INSERT Foo OFF",
session.Connection as SqlConnection)
.ExecuteNonQuery();
}
Although I set Identity_Insert to ON, I get the following exception (when keeping ID and setting new ValidFrom):
Cannot insert explicit value for identity column in table 'Foo' when IDENTITY_INSERT is set to OFF.
This is the SQL executed:
INSERT INTO Foo (C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, Id, ValidFrom)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Can anyone explain why I still get that exception?

If the problem has to do with separate transactions like Nathan Fisher suggested, then NHibernate's ITransaction.Enlist(IDbCommand) method should fix it. Try something like this:
using (var trx = session.BeginTransaction())
{
ExecuteInNHTransaction(session, "SET IDENTITY_INSERT Foo ON");
session.Save(myFoo);
ExecuteInNHTransaction(session, "SET IDENTITY_INSERT Foo OFF");
trx.Commit();
}
private static void ExecuteInNHTransaction(ISession session, string commandText)
{
var command = new SqlCommand(commandText,
(SqlConnection) session.Connection);
session.Transaction.Enlist(command);
command.ExecuteNonQuery();
}

Related

SqfliteDatabaseException when trying to insert into a database

I am trying to insert a new note into a database with the following flutter code. final noteId = await db.insert(noteTable, { userIDColumn: owner.id, textColumn: text, isSyncedWithCloudColumn: 1, });
I get the following exception Exception has occurred. SqfliteDatabaseException (DatabaseException(NOT NULL constraint failed: note.id (code 1299 SQLITE_CONSTRAINT_NOTNULL)) sql 'INSERT INTO note (user_id, text, is_synced_with_cloud) VALUES (?, ?, ?)' args [1, , 1])
I tried the code described above and got the exception instead of a successful result.

SQLite prepare method fails due to syntax error

So I want to create a database for Users and insert values into the fields using variable. Initially I tried using it calling the do function, but it wasn't reading the variables properly so I decided to just use prepare and execute separately. This is my code:
$dbh->do("DROP TABLE IF EXISTS Users");
$dbh->do("CREATE TABLE Users(
zid TEXT,
Name TEXT,
Email TEXT,
password TEXT,
Mates TEXT,
Program TEXT,
Courses TEXT,
Suburb TEXT,
Birthday TEXT)");
$zid = "z33432523";
$name = "John Doe";
$email = "email#gmail.com";
$password = "alien";
$mates = "z3459148 z3458291";
$program = "";
$courses = "";
$suburb = "";
$birthday = "13/5/1992";
$sth = $dbh->prepare('INSERT INTO Users VALUES (?, ?, ?, ?, ?. ?, ?, ?, ?)');
$sth->execute($zid, $name, $email, $password, $mates, $program, $courses, $suburb, $birthday);
$dbh->disconnect();
However, if I try running this code I get the following error:
DBD::SQLite::db prepare failed: near ".": syntax error at ./dbm.pl line 35.
I'm not sure exactly what the problem is?
near ".": syntax error
INSERT INTO Users VALUES (?, ?, ?, ?, ?. ?, ?, ?, ?)
^

Service Stack OrmLite and Identity_Insert

When using Service Stack OrmLite how do you insert identity values exactly?
For instance in SQL Server when Identity_Insert is turned on for a table the identity value will be inserted exactly as specified and will not instead be auto generated.
Do not decorate your primary key with the [AutoIncrement] attribute. If you do so, then OrmLite will leave that column name and value out of the INSERT statement.
Issue the SET IDENTITY_INSERT statement. Make sure to let OrmLite build the table name for you, taking into account any [Schema] and [Alias] attributes.
For example:
public void InsertAll(IEnumerable<TTable> set)
{
const string identity = "SET IDENTITY_INSERT {0} {1}";
var schema = typeof(TTable).FirstAttribute<SchemaAttribute>();
var tableName = typeof(TTable).FirstAttribute<AliasAttribute>();
var qualified = (schema == null ? "dbo" : schema.Name) + "." +
(tableName == null ? typeof(TTable).Name : tableName.Name);
using (var db = _dbConnectionFactory.OpenDbConnection())
{
try
{
db.ExecuteSql(string.Format(identity, qualified, "ON"));
db.InsertAll(set);
}
finally
{
db.ExecuteSql(string.Format(identity, qualified, "OFF"));
}
});
}

How to organize WebOS SQL code that depends on previous results?

I want to do a simple WebOS Mojo app that adds dates to a database, but before that it needs to check few conditions by interrogating the database. Given the asynchronous mode of accessing the database in WebOS I'm wondering what is the most efficient and short way of writing such code.
For example I need to make sure the new date is not already in the database. Then I need to get the closest date so that I can compute the difference in days and throw an error if the difference is too small. Then I need to insert the new date and then compute an average.
This would be easy to do in a synchronous way of accessing the db, but I don't really like the idea of writing parts of the code in multiple success handlers of the different sql statements executed. Is there a more elegant solution?
You can use inline callbacks to the HTML 5 relational database functions:
function createProject(project, onSuccess) {
if (project.projectId)
throw new StorageError("project already exists");
if (project.path)
throw new StorageError("project already has a path");
project.projectId = ++Tracker.maxLocalId * 4096;
project.path = calcNextProjectPath();
project.normalize();
Tracker.db.transaction(
function (transaction) {
transaction.executeSql(
"INSERT OR ROLLBACK INTO item (dbId, path, hasChildren, kind, summaryText, place, work, responsible, responsibleClass) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
[project.projectId, project.path, project.hasChildren, project.kind, project.title, project.place, project.work, project.responsible, project.responsibleClass],
function (transaction, resultSet) {
Mojo.Log.info("DB: inserted new project item", resultSet.insertId, project.title);
transaction.executeSql(
"INSERT OR ROLLBACK INTO project (projectId, accountId, title, backendKind, backendStatus, backendLastChanged, lastSuccessfulDown) \
VALUES (?, ?, ?, ?, ?, ?, ?)",
[project.projectId, project.accountId, project.title, project.backendKind, project.backendStatus, project.backendLastChanged, project.lastSuccessfulDown],
function (transaction, resultSet) {
Warn.logInfo("created new project", "projectId=" + resultSet.insertId, project.title);
if (onSuccess)
onSuccess();
},
function (transaction, sqlError) {
Warn.bannerError("create", $L("Quit and reset your phone."), "project row insertion failed: ", sqlError.message, sqlError.code, project);
return true; // abort whole transaction
}
);
},
function (transaction, sqlError) { // failure of insert project item
if (sqlError.code === 1 && sqlError.message === "constraint failed" && Mojo.appInfo.id !== "com.outlinetracker.outlinetracker") {
upgradeAlert(true);
} else {
Warn.bannerError("create", $L("Quit and reset your phone."), "project item insertion failed: ", sqlError.message, sqlError.code);
}
return true; // abort whole transaction
}
);
}, // end transaction function
function (sqlError) { // seems to only be called for exceptions in callbacks
Warn.logError($L("Quit and reset your phone."), "transaction 'insert project' failed", sqlError.message, sqlError.code);
}
); // end transaction call
}

How to save byte[] using a procedure?

This stored procedure does not save the data, it seems to be a problem with the VARBINARY. I am passing a byte[] to it, but then it doesn't work. If I send this parameter as NULL it works.
I'm calling the procedure with the following code:
public Community AddCommunity(string name, string description, byte[] picture, User owner, int? venue, int communityID)
{
using (var database = new Database())
{
return database.Scope.GetSqlQuery<Community>("QP_AddCommunity ?, ?, ?, ?, ?, ?", "VARCHAR Name, VARCHAR Description, VARBINARY Picture, INTEGER Owner, INTEGER Venue, INTEGER ID").GetResult(name, description, picture, owner.ID, venue, communityID);
}
}
The procedure is the following:
CREATE PROCEDURE [dbo].[QP_AddCommunity]
#Name VARCHAR(120),
#Description VARCHAR(MAX),
#Picture VARBINARY(MAX),
#Owner INTEGER,
#Venue INTEGER,
#ID INTEGER
AS
BEGIN
SET NOCOUNT ON;
IF(SELECT COUNT(*) FROM QT_Community WHERE ID = #ID) = 0
INSERT INTO QT_Community(Name, [Description], Picture, [Owner], Venue) VALUES(#Name, #Description, #Picture, #Owner, #Venue);
ELSE
UPDATE QT_Community SET Name = #Name, [Description] = #Description, Picture = #Picture, [Owner] = #Owner, Venue = #Venue WHERE ID = #ID;
SELECT * FROM QT_Community WHERE ID = ##IDENTITY;
END
What's wrong with this code? Isn't VARBINARY a byte[] ?
This code works when executing on SQL Server Management Studio.
DECLARE #X varbinary(20)
Set #X = CAST('Testing' As varbinary(20))
EXECUTE [QP_AddCommunity] 'aaaaa', 'descricao', #X, 216, NULL, 0;
But when calling from the GetSqlQuery method with something on the byte[] the transaction says it's not active and not dirty. BUT if the byte[] is null it works as it should.
i found that it is impossible as this answer shows
Hello gaurav, currently our
GetSqlQuery method cannot operate
properly with parameters of type
LongVarBinary or VarBinary, thus
making it impossible for the stored
procedure to work as expected. We are
aware of this problem and we are
working on fixing it. As a work around
you should try and use Linq to achieve
your goal. Greetings, Petar the
Telerik team
Accordingly to this table it seems either BLOB, BINARY, VARBINARY would be valid types for [] of primitive type.
You could try to ask on their forums, maybe someone will be able to help you.
Try using the .WRITE method. On your INSERT, insert 0x for Picture, then update independently.
UPDATE QT_Community
SET Picture.Write (#Picture, 0, DATALENGTH(Picture))
WHERE ID = #ID
Example (Ado.Net):
byte[] ba = UlongsToBytes(ul);
try
{
string source = #"packet size=4096;integrated security=SSPI;data source=MyPC\MyNamedInstance;persist security info=False;initial catalog=Sandbox";
SqlConnection conn = new SqlConnection(source);
conn.Open();
SqlCommand a = new SqlCommand("INSERT BigintsTarget(bi) SELECT * FROM dbo.ParseImageIntoBIGINTs(#BIGINTs)", conn);
a.CommandType = System.Data.CommandType.Text;
a.Parameters.Add(new SqlParameter("#BIGINTs", System.Data.SqlDbType.Image,2147483647));
for(int q=0; q<10; q++)
{
a.Parameters[0].Value = ba;
int res = a.ExecuteNonQuery();
}
d2 = DateTime.Now;
SqlCommand b = new SqlCommand("INSERT BigintsTarget1(bi) SELECT * FROM dbo.ParseVarcharMAXIntoBIGINTs(#BIGINTs)", conn);
b.CommandType = System.Data.CommandType.Text;
b.Parameters.Add(new SqlParameter("#BIGINTs", System.Data.SqlDbType.VarChar,2147483647));
for(int q=0; q<10; q++)
{
b.Parameters[0].Value = sss;
int res = b.ExecuteNonQuery();
}
//b.ExecuteNonQuery();
conn.Close();
}
catch(Exception ex)
{
string s = ex.Message;
int t=0;
t++;
}
}

Resources