NHibernate HiLo ID Generator. Generating an ID bef

2020-02-10 10:08发布

I'm trying to use 'adonet.batch_size' property in NHibernate. Now, I'm creating entities across multiple sessions at a large rate (hence batch inserting). So what I'm doing is creating a buffer where I keep these entities and them flush them out all at once periodically.

However I need the ID's as soon as I create the entities. So I want to create an entity (in any session) and then have its ID generated (I'm using HiLo generator). And then at a later time (and other session) I want to flush that buffer and ensure that those IDs do not change.

Is there anyway to do this?

Thanks

Guido

标签: nhibernate
1条回答
够拽才男人
2楼-- · 2020-02-10 10:48

I find it odd that you need many sessions to do a single job. Normally a single session is enough to do all work.

That said, the Hilo generator sets the id property on the entity when calling nhSession.Save(object) without necessarily requiring a round-trip to the database and a nhSession.Flush() will flush the inserts to the database

UPDATE ===========================================================================

This is a method i used on a specific case that made pure-sql inserts while maintaining NHibernate compatibility.

//this will get the value and update the hi-lo value repository in the datastore
public static void GenerateIdentifier(object target)
{
      var targetType = target.GetType();
      var classMapping = NHibernateSessionManager.Instance.Configuration.GetClassMapping(targetType);
      var impl = NHibernateSessionManager.Instance.GetSession().GetSessionImplementation();

      var newId = classMapping.Identifier.CreateIdentifierGenerator(impl.Factory.Dialect, classMapping.Table.Catalog, classMapping.Table.Schema,
                                                              classMapping.RootClazz).Generate(impl, target);
      classMapping.IdentifierProperty.GetSetter(targetType).Set(target, newId);
}

So, this method takes your newly constructed entity like

var myEnt = new MyEnt(); //has default identifier
GenerateIdentifier(myEnt); //now has identifier injected based on nhibernate's mapping

note that this call does not place the entity in any kind of nhibernate managed space. So you still have to make a place to place your objects and make the save on each one. Also note that i used this one with pure sql inserts and unless you specify generator="assigned" (which will then require some custom hi-lo generator) in your entity mapping nhibernate may require a different mechanism to persist it.

All in all, what you want is to generate an Id for an object that will be persisted at some time in the future. This brings up some problems such as handling non-existent entries due to rollbacks and failed commits. Additionally imo nhibernate is not the tool for this particular job, you don't need nhibernate to do your bulk insert unless there is some complex entity logic that is too costly (in dev time) to implement on your own.

Also note that you are implying that you need transient detached entities which however cannot be used unless you call .nhSes.Save(obj) on the first session and flush its contents so the 2nd session when it calls Load on the transient object there will be an existing row in the database which contradicts what you want to achieve.

Imo don't be afraid of storming the database, just optimise the procedure top-to-bottom to be able to handle the volume. Using nhibernate just to do an insert seems counter-productive when you can achieve the same result with 4 times the performance using ado.net or even an isqlquery wrapped-query (and use the method i provided above)

查看更多
登录 后发表回答