If I have an entity Foo which I'm persisting using NHibernate and I retrieve it using Linq like so:
var foos = FooRepository.GetFoos.Where(x => x.LikesWearningFunnyHats == true);
I then dirty each Foo like so:
foo.LikesWearingFunnyHats = false;
And tell the repository to save it:
FooRepository.Save(foo);
I'm currently finding that the Foos are NOT being saved. Is this because I'm retrieving them using Linq rather than by ID or through an association?
It shouldn't be because you're using Linq. The Linq expression tree is just translated into the same ANTLR primitives that an IQuery or HQL string would be, and from there to SQL.
Make sure you're flushing the Session, and/or committing the Transaction inherent in that Session, after completing a persistence operation. You should understand that NHibernate provides a layer of separation between you and the database, and is designed to decide when to send updates to the DB, to economize on round trips to the DB server. Usually, it does so in "batches"; it'll collect ten or twenty statements before pushing them as one batch to SQL Server. If you're doing smaller units of work than that at one time, you must override its decision to hold off on sending the update by forcing the session to perform a SQL update, using the ForceFlush() method.
It would be best to make this externally controllable, by exposing methods of the Session or its containing Repository to create, commit and rollback transactions within the Session.
Why do you think is not actually saved ? Try to call session.Flush() and ensure committing the transaction to see if NH will issue the proper command. Event strategy for fetching the entity should not matter.
Related
I have an object with a cascaded list which is mapped in the following way:
HasMany(x => x.Products).Cascade.AllDeleteOrphan(); //.BatchSize(10000);
After adding 20000 products to the list, the commit takes more then 30 seconds (while it should be max 3 seconds).
What I need is a kind of bulk insert. I could follow this approach: Speed up bulk insert operations with NHibernate. I know this solution uses the StatelessSession but anyway, my hope is to configure these things in my mapping, adding objects directly to the list in my Entity and NHibernate takes care of the remaining stuff. Setting the BatchSize on the mapping of the list seems to has no effect.
Is there any way to accomplish this task in an acceptable time?
I think that batch size in the mapping is only related to fetching. You can try using this configuration in your nhibernate config:
<property name="adonet.batch_size">250</property>
the only to speed things up is use stateless session
(read this: Inserts of stateless session of NHibernate are slow)
also, take care of below - to make it even more faster
cfg.AutoCommentSql = false;
cfg.LogFormattedSql = false;
My project uses EF (tested with version 4 using self-tracking template and with version 5 using default templates, all database-first) against SQL Server 2012. The database tables have each a rowversion (timestamp) column defined.
Using EF in it core, meaning my code on database updates looking so:
using (var db = new MyContext())
{
//db.Entry(myInstance).State = EntityState.Modified;
db.SaveChanges();
}
does not trigger any rowversion alerts. I run parallel clients, each reads the same record, makes a change to it and then each writes it to the database. All updates are accepted, no concurrency is applied.
Do I have to work with stored procedures for my update commands (with a where clause that states my rowversion value) to have EF acknowledge the "built-in" concurrency or is there another way (configuration, specific method calls) to make my code work?
Here's the answer (I've given it a couple of weeks to POC):
RowVersion (or the TimeStamp field type) in SQL is a field as any other (except for being mandatory and self incrementing). There is a specific database handling of its value on updates (i.e. incrementing it), but there is no specific database handling comparing its value before update.
EF on the other side allows you to define ConcurrencyMode for each field (edmx). You might, if you want, mark all your fields with ConcurrencyMode=Fix (instead of the default None), and thus include all of them within the update's where-clause (comparing the entity's original values with the record's current values in the database). But it's easier to set one field per entity, i.e. the RowVersion field, with that mode. Especially since the only party maintaining it for you is the database.
Once you've done that, you're sure to get the System.Data.OptimisticConcurrencyException isolation error. You still have to keep away from EF workflows which manipulate your object sets, such as the use of myObjectSet.Attach(myEntity), which makes a trip to the database to fetch the current data and merges your changes into it. Since the RowVersion field is normally unchanged, the update will trigger with the current value from the database, and will not result in the concurrency exception.
Are you looking to handle concurrency if so take a look at this link:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application
As per the performance tip in Rhom API of Rhomobile,
We should prepare the whole data set first and then call the create/update_attributes for better performance over preparing single record then calling create inside loop.
As per my knowledge, create method takes the object of single record as like this,
#account = Account.create(
{"name" => "some new record", "industry" => "electronics"}
)
So i wonder how to create/update multiple records on a single call?
Thanks in advance.
First, I have no idea how much this will actually affect performance, whether positively or negatively, and have never measured it.
That said, you can wrap all the CRUD calls in a transaction, to minimise the DB connections opened and closed. This can also help you with maintaining referential integrity, by rolling back changes if some record is causing a problem with your new dataset.
# Load all DB Models, to ensure they are available before first time import
Rho::RHO.load_all_sources();
# Get instance of DB to work transactions with
db = ::Rho::RHO.get_db_partitions()['local'] # Get reference to model db
db.start_transaction() # BEGIN transaction
... Do all your create/update/deletes
if (was_import_successful)
db.commit # COMMIT transaction
else
db.rollback() # ROLLBACK transaction
end
Using Rhom, you can still write SQL queries for the underlying SQLite engine. But you need to understand what is the Table format you're using.
The default PropertyBags data model are all stored in a key value store in a single Table, if you're looking for the maximum performance, you better switch to FixedSchema data models. In this case you loose some flexibility but you gain some performance and you save same space.
My suggestion is to use transactions, like you're already doing, switch to FixedSchema data models and see if you're fine in that way. If you really need to increase the speed, maybe you can achieve what you want in a different way, something like importing a SQLite database created on the server side.
This is the method that RhoConnect uses for the bulk synchronization.
I have a fairly large EF4 model, using POCO code gen. I've got lots of instances where I select a single entity from whichever table by its ID.
However on some tables, this takes 2 minutes or more, where on most tables it takes less than a second. I'm out of ideas as to where to look now, because I can't see any reason. It's always the same tables that cause problems, but I can query them directly against the database without problems, so it must be somewhere in Entity Framework territory that the problem is coming from.
The line is the quite innoccuous:
Dim newProd As New Product
Product.ShippingSize = Entities.ShippingSizes.Single(Function(ss) ss.Id = id)
id is simply an integer passed in from the UI, Id on my entity is the primary key, which is indexed on the database
Entities is a freshly created instance of my entity framework datacontext
This is not the first query being executed against the Context, it is the first query against this EntitySet though
I have re-indexed all tables having seen posts suggesting that a corrupt index could cause slow access, that hasn't made any difference
The exact same line of code against other tables runs almost instantly, it's only certain tables
This particular table is tiny - it only has 4 things in it
Any suggestions as to where to even start?
--edit - I'd oversimplified the code in the question to the point where the problem disappeared!
Where to start?
Print or log the actual SQL string that's being sent to the database.
Execute that literal string on the server and measure its performance.
Use your server's EXPLAIN plan system to see what the server's actually doing.
Compare the raw SQL performance to your EF performance.
That should tell you whether you have a database problem or an EF problem.
Seems like this is a function of the POCO template's Fixup behaviour in combination with lazy loading.
Because the entity has already been loaded via Single, subsequent operations seem to be happening in memory rather than against the database. The Fixup method by default makes Contains() calls, which is where everything grinds to a halt while 10s of thousands of items get retrieved, initialised as proxies, and evaluated in memory.
I tried changing this Contains() to a Where(Function(x) x.Id = id).Count > 0 (will do logically the same thing, but trying to force a quick DB operation instead of the slow in-memory one). The query was still performed in-memory, and just as slow.
I switched from POCO to the standard EntityGenerator, and this problem just disappeared with no other changes. Say what you will about patterns/practices, but this is a nasty problem to have - I didn't spot this until I switched from fakes and small test databases to a full size database. Entity Generator saves the day for now.
I have a situation where I want to do some DB-related operations in a Java application (e.g. on Eclipse). I use MySQL as a RDBMS and Hibernate as an ORM provider.
I retreive all records using embedded SQL in Java:
//Define conncections ...etc
ResultSet result = myStmt.executeQuery("SELECT * FROM employees");
// iterator
I retreive all records using Hibernate ORM / JPQL:
// Connections,Entity Manager....etc
List result = em.createQuery("SELECT emp FROM Employees emp").getResultList();
// iterator
I know that the RDMS is located on secondary-memory (DISK). The question is, when I get both results back. Where are the employees actually? On the secondary (SM) or on main-memory (MM)?
I want to have at the end two object populations for further testing, one operating on the SM and one on the MM? How is this possible?
Thanks
Frank
Your Java Objects are real Java Objects, they are in (to use your term) MM, at least for a while. The beauty of the Hbernate/JPA programming model is that while in MM you can pretty much treat the objects as if they were any other Java object, make a few changes to them etc. And then at some agreed time Hibernate's persistence mechansim gets them bask to, SM (disk).
You will need to read up on the implications of Sessions and Transactions in order to understand when the transitions between MM and SM occur, and also very importantly, what happens if two users want to work with the same data at the same time.
Maybe start here
It is also possible to create objects in MM that are (at least for now) not related to any data on disk - these are "transient" objects, and also to "disconnect" data in memeory from what's on disk.
My bottom line here is that Hibernate/JPA does remove much grunt work from persistence coding, but it cannot hide the complexity of scale, as your data volumes increase, your data model's complexity grows and your user's actions contend for data you need to do serious thinking. Hibernate allows you to achive good things, but it can't do that thinking for you, you have to make careful choices as your problem domain gets more complex.