Nhibernate update integer field = field+1 - nhibernate

I have a simple integer field mapped in nhibernate.
I want to make an update that nhibernate will translate it to +1;
UPDATE table_name SET revision=revision + 1 [WHERE Clause]....
Is it possible to make such thing? Force nhibernate incrementing field by N on update?

In case, that you are talking about "make update without loading the entity", the answer is yes, we do have DML: 13.3. DML-style operations. Small extract:
... automatic and transparent object/relational mapping is concerned with the management of object state. This implies that the object state is available in memory, hence manipulating (using the SQL Data Manipulation Language (DML) statements: INSERT, UPDATE, DELETE) data directly in the database will not affect in-memory state. However, NHibernate provides methods for bulk SQL-style DML statement execution which are performed through the Hibernate Query Language (HQL)...
It is a way, how to use the mapping we have, creating the HQL describing the update, execute this on the DB Engine directly, without any data load.
Converted example:
ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();
string hqlUpdate = "update TheMappedEntity e set e.Revision=(e.Revision + 1) where...";
int updatedEntities = s.CreateQuery( hqlUpdate )
.SetString( ... // set params
.ExecuteUpdate();
tx.Commit();
session.Close();
The biggest advantage is that we are working with the Entity (mapped one) not with raw SQL

Related

NHibernate generates INSERT and UPDATE for new entity

I have an entity with Id column generated using Hilo.
I have a transaction, creating a new entity and calling SaveOrUpdate() in order to get the Hilo generated Id of the entity (I need to write that Id to another DB).
later on, within the same transaction I update the new entity, just a simple update of a simple property, and in the end I call SaveOrUpdate() again.
I see that the SQL commands generated are first INSERT and then an UPDATE, but what I want is just an INSERT with the final details of the entity. is that possible? am I doing something wrong?
EDIT: added code sample
here's a very simplified example of pseudo code:
Person newPerson = new Person(); // Person is a mapped entity
newPerson.Name = "foo";
_session.SaveOrUpdate(newPerson); // generates INSERT statement
newPerson.BirthDate = DateTime.Now;
_session.SaveOrUpdate(newPerson); // generates UPDATE statement
// assume session transaction was opened before and disposed correctly for sake of simplicity
_session.Transaction.Commit();
The point is that with ORM tools like NHibernate, we are working different way, then we did with ADO.NET.
While ADO.NET Commands and their Execute() method family would cause immediate SQL statement execution on the DB server... with NHibernate it is dramatically different.
We are working with a ISession. The session, could be thought as a C# collection in a memory. All the Save(), SaveOrUdpate(), Update(), Delete() ... calls are executed against that object representation. NO SQL Command is executed, when calling these methods, no low-level ADO.NET calls at the moment.
That abstraction allows NHibernate to optimize the final SQL Statement batch... based on all the information gathered in the ISession. And that's why, you will never see INSERT, UPDATE if working with one Session, unless we explictly call the magical Flush() or change the FlushMode at all.
In that case (calling Flush() ), we are trying to say: NHibernate we are smart enough, now is the time to execute commands. In other scenarios, usually it is good enough to leave it on NHibernate...
See here:
- 9.6. Flush

how perform batch operation with dapper orm?

I Have dapper orm in project and i have save alto of data (1200000row) in database but in transaction with dapper is very slow i want fast.with nhibernate (session statetless)is slow.
I think dapper is fast because that fetch data(700000) with nhibernate in 33 second that with dapper in 9 second.
how solved problem ?
my code is :
IDbTransaction trans = connection.BeginTransaction();
connection.Execute(#"
insert DailyResult(Id, PersonId,DateTaradod,DailyTaradods)
values(#Id, #PersonId,#DateTaradod,#DailyTaradods)", entity, trans);
trans.Commit();
There is no mechanism to make inserting 1200000 rows in a transaction instant, via any regular ADO.NET API. That simply isn't what the intent of that API is.
For what you want, it sounds like you should be using SqlBulkCopy. This supports transactions, and you can use FastMember to help here; for example:
IEnumerable<YourEntity> source = ...
using(var bcp = new SqlBulkCopy(
connection, SqlBulkCopyOptions.UseInternalTransaction))
using(var reader = ObjectReader.Create(source,
"Id", "PersonId", "DateTaradod", "DailyTaradods"))
{
bcp.DestinationTableName = "DailyResult";
bcp.WriteToServer(reader);
}
It also supports external transactions, but if you are going to "create tran, push, commit tran" you might as well use the internal transaction.
If you don't want to use SqlBulkCopy, you can also look at table-valued-parameter approaches, but SqlBulkCopy would be my recommended API when dealing with this volume.
Note: if the table has more columns than Id, PersonId, DateTaradod and DailyTaradods, you can specify explicit bcp.ColumnMappings to tweak how the insert behaves.

nhibernate one isession same idbconnection

I have some code doing 2 times session.Get(id) on the same ISession. I can see that the ISession creates 2 idbconnections. I guess this is because of some kind of configuration. I would like it to do the fetch on the same idbconnection. How?
If both Get operations are in the same transaction, they will share the same IDbConnection. Otherwise you end up with implicit transactions and NHibernate will open and close an IDbConnection for each query. In general, you should try do something like:
using (var tx = session.BeginTransaction())
{
var customer = session.Get<Customer>(123);
var order = session.Get<Order>(456);
// do stuff
tx.Commit();
}
Use of implicit transactions is discouraged:
When we don't define our own
transactions, it falls back into
implicit transaction mode, where every
statement to the database runs in its
own transaction, resulting in a large
performance cost (database time to
build and tear down transactions), and
reduced consistency.
Even if we are only reading data, we
should use a transaction, because
using transactions ensures that we get
consistent results from the database.
NHibernate assumes that all access to
the database is done under a
transaction, and strongly discourages
any use of the session without a
transaction.

NHibernate Flush-- How it works?

I am kind of confused on how Flush ( and NHibernate.ISession) in NHibernate works.
From my code, it seems that when I saved an object by using ISession.Save(entity), the object can be saved directly to the database.
However, when I update and object using ISession.SaveOrUpdate(entity) or ISession.Update(entity), the object in the database is not updated--- I need to call ISession.Flush in order to update it.
The procedure on how I update the object is as follows:
Obtain the object from the database by using ISession.Get(typeof(T), id)
Change the object property, for example, myCar.Color="Green"
Commit it back to the database by using ISession.Update(myCar)
The myCar is not updated to database. However, if I call ISession.Flush afterwards, then it is updated.
When to use Flush, and when not to use it?
In many cases you don't have to care when NHibernate flushes.
You only need to call flush if you created your own connection because NHibernate doesn't know when you commit on it.
What is really important for you is the transaction. During the transaction, you are isolated from other transactions, this means, you always see your changes when you read form the database, and you don't see others changes (unless they are committed). So you don't have to care when NHibernate updates data in the database unless it is committed. It is not visible to anyone anyway.
NHibernate flushes if
you call commit
before queries to ensure that you filter by the actual state in memory
when you call flush
Example:
using (session = factory.CreateSession())
using (session.BeginTransaction())
{
var entity = session.Get<Entity>(2);
entity.Name = "new name";
// there is no update. NHibernate flushes the changes.
session.Transaction.Commit();
session.Close();
}
The entity is updated on commit. NHibernate sees that your session is dirty and flushes the changes to the database. You need update and save only if you made the changes outside of the session. (This means with a detached entity, that is an entity that is not known by the session).
Notes on performance: Flush not only performs the required SQL statements to update the database. It also searches for changes in memory. Since there is no dirty flag on POCOs, it needs to compare every property of every object in the session to its first level cache. This may become a performance problem when it is done too often. There are a couple of things you can do to avoid performance problems:
Do not flush in loops
Avoid serialized objects (serialization is required to check for changes)
Use read-only entities when appropriate
Set mutable = false when appropriate
When using custom types in properties, implement efficient Equals methods
Carefully disable auto-flush when you are sure that you know what you are doing.
NHibernate will only perform SQL statements when it is necessary. It will postpone the execution of SQL statements as long as possible.
For instance, when you save an entity which has an assigned id, it will likely postpone the executin of the INSERT statement.
However, when you insert an entity which has an auto-increment id for instance, then NHibernate needs to INSERT the entity directly, since it has to know the id that will be assigned to this entity.
When you explicitly call flush, then NHibernate will execute the SQL statements that are necessary for objects that have been changed / created / deleted in that session.
Flush

NHibernate: exclusive locking

In NHibernate, I want to retrieve an instance, and put an exclusive lock on the record that represents the retrieved entity on the database.
Right now, I have this code:
With.Transaction (session, IsolationLevel.Serializable, delegate
{
ICriteria crit = session.CreateCriteria (typeof (TarificationProfile));
crit.SetLockMode (LockMode.Upgrade);
crit.Add (Expression.Eq ("Id", tarificationProfileId));
TarificationProfile profile = crit.UniqueResult<TarificationProfile> ();
nextNumber = profile.AttestCounter;
profile.AttestCounter++;
session.SaveOrUpdate (profile);
});
As you can see, I set the LockMode for this Criteria to 'Upgrade'.
This issues an SQL statement for SQL Server which uses the updlock and rowlock locking hints:
SELECT ... FROM MyTable with (updlock, rowlock)
However, I want to be able to use a real exclusive lock. That is, prevent that others can read this very same record, until I have released the lock.
In other words, I want to be able to use an xlock locking hint, instead of an updlock.
I don't know how (or even if) I can achieve that .... Maybe somebody can give me some hints about this :)
If it is really necessary, I can use the SQLQuery functionality of NHibernate, and write my own SQL Query, but, I'd like to avoid that as much as possible.
A HQL DML query will accomplish your update without needing a lock.
This is available in NHibernate 2.1, but is not yet in the reference documentation. The Java hibernate documentation is very close to the NHibernate implementation.
Assuming you are using ReadCommitted Isolation, you can then safely read your value back inside the transaction.
With.Transaction (session, IsolationLevel.Serializable, delegate
{
session.CreateQuery( "update TarificationProfile t set t.AttestCounter = 1 + t.AttestCounter where t.id=:id" )
.SetInt32("id", tarificationProfileId)
.ExecuteUpdate();
nextNumber = session.CreateQuery( "select AttestCounter from TarificationProfile where Id=:id" )
.SetInt32("id", id )
.UniqueResult<int>();
}
Depending on your table and column names, the generated SQL will be:
update TarificationProfile
set AttestCounter = 1 + AttestCounter
where Id = 1 /* #p0 */
select tarificati0_.AttestCounter as col_0_0_
from TarificationProfile tarificati0_
where tarificati0_.Id = 1 /* #p0 */
I doubt it can be done from NHibernate. Personally, I would use a stored procedure to do what you're trying to accomplish.
Update: Given the continued downvotes I'll expand on this. Frederick is asking how to use locking hints, which are syntax- and implementation-specific details of his underlying database engine, from his ORM layer. This is the wrong level to attempt to perform such an operation - even if it was possible (it isn't), the likelihood it would ever work consistently across all NHibernate-supported databases is vanishingly low.
It's great Frederick's eventual solution didn't require pre-emptive exclusive locks (which kill performance and are generally a bad idea unless you know what you're doing), but my answer is valid. Anyone who stumbles across this question and wants to do exclusive-lock-on-read from NHibernate - firstly: don't, secondly: if you have to, use a stored procedure or a SQLQuery.
If all you read are done with a IsolationLevel of Serializable and all the write are also done with a IsolationLevel of Serializable I don't see why you need to do any locking of database rows your self.
So the serialize keeps the data safe, now we still have the problem of possible dead locks....
If the deadlocks are not common, just putting the [start transaction, read, update, save] in a retry loop when you get a deadlock may be good enough.
Otherwise a simple “select for update” statement generated directly (e.g. not with nhibernate) could be used to stop another transaction reading the row before it is changed.
However I keep thinking, that if the update rate is fast enough to get lots of deadlocks a ORM may not be the correct tool for the update, or the database schema may need redesigning to avoid the value that has to be read/written (e.g calculation it when reading the data)
You could use isolation level "repeatable read" if you want to make sure that values you read from the database don't change during the transaction. But you have to do this in all critical transactions. Or you lock it in the critical reading transaction with an upgrade lock.