Hibernate:Difference between setting the Id directly in the bean or calling the load() or get() method?

纵然是瞬间 提交于 2020-01-02 16:29:53

问题


Following is an example of load:-

Stock stock = (Stock)session.load(Stock.class, new Integer(2));
           StockTransaction stockTransactions = new StockTransaction();
           //set stockTransactions detail
           stockTransactions.setStock(stock);        
           session.save(stockTransactions);

What is the difference if i directely set the id in like:-

Stock stock =new Stock();
stock.setId(2);
 StockTransaction stockTransactions = new StockTransaction();
               //set stockTransactions detail
               stockTransactions.setStock(stock);        
               session.save(stockTransactions);

As i already know the Id of the stock table. Y call the load or get?


回答1:


What is the difference ...

Your first sample of code fetches object from database, thus loaded object will be in persisted state. Your second sample will try to save StockTransaction with completely new Stock. This may lead to primary key errors (if stock id is unique) or duplicate entries. You should base the choice of which way to use on your requirements. If you need StockTransaction with existing Stock (I assume this is your case as you wrote that you know ID) - you should load it from database first.

Y call the load or get?

Session.load() will return a proxy with empty fields, if there is no such object (with such id) in the database.

Session.get() will return null if there is no object with such id.

Which one to use is up to you and your task. Personally I prefer get().




回答2:


The object create will be in persistent State.

 Stock stock = (Stock)session.load(Stock.class, new Integer(2));

The object create will be in transient State.

Stock stock =new Stock();
stock.setId(2);

Transient State:

A New instance of a persistent class which is not associated with a Session, has no representation in the database and no identifier value is considered transient by Hibernate:

Persistent State:

A persistent instance has a representation in the database , an identifier value and is associated with a Session. You can make a transient instance persistent by associating it with a Session:

REFERENCE

http://www.dineshonjava.com/p/transient-persistent-and-detached.html#.U4LKlHakrlc




回答3:


Although it's not that common if you only plan on saving the child entity (StockTransaction) than both methods will yield the same result. You will get the child persisted and after a flush the parent is going to be attached to the current Session.

I created a test on GitHub:

final Long parentId = cleanAndSaveParent();
transactionTemplate.execute(new TransactionCallback<Void>() {
        @Override
        public Void doInTransaction(TransactionStatus transactionStatus) {
            SetParent idOnlyParent = new SetParent();
            idOnlyParent.setId(parentId);
            SetChild newChild = new SetChild();
            newChild.setName("new");
            newChild.setParent(idOnlyParent);
            entityManager.persist(newChild);
            entityManager.flush();
            SetChild otherChild = new SetChild();
            otherChild.setName("Other");
            idOnlyParent.addChild(otherChild);
            entityManager.flush();
            assertEquals(1, idOnlyParent.getChildren().size());
            return null;
        }
    });

    transactionTemplate.execute(new TransactionCallback<Void>() {
        @Override
        public Void doInTransaction(TransactionStatus transactionStatus) {
            SetParent parent = entityManager.find(SetParent.class, parentId);
            assertEquals(3, parent.getChildren().size());
            return null;
        }
    });

When flush() is called the newChild object will become attached to the current Session. But the parent isn't going to be attached, so changes to the parent side won't be synchronized at all.

If the parent was fetched from the DB, then changed to the parent would have been "dirty checked" and synchronized at flush time.

Even if it's possible to do it, it's not really advisable. It may get you the false impression that you are still working with an attached parent entity, while you only get a transient parent.




回答4:


To correctly synchronize the object state with database the objects needs to be managed by hibernate ( aka associated with persistence context). At the flush time it is the content of persistence context which decides what is going to be flushed to database and then committed. Apart from that relationships are always created between persistent entities. The persistent nature may be explicit (by calling any of the appropriate API method - save,update,merge etc in native hibernate or their JPA counterparts) or implicit (due to cascade property or by virtue of being loaded by appropriate API call like load, get etc). Another reason for the entities being persistent is write-behind transactional nature where you can keep modifying the state of object and the delta is propagated to the database in the end at transaction commit time or explicit flush. In an object graph what needs to be propagated to the database depends upon what objects are managed or persistent (both terms used interchangeably most of the time). There is a concept of detached objects ( objects which have their database identifier set but are no guaranteed to represent the actual state in database. Actually any data can be potentially stale outside transaction). For these too you have option of reattaching / merging to persistence context ( in native hibernate) or merging (in JPA ).

Also while creating bidirectional relationships - another concept needs to be taken into consideration - inverse. The inverse side is not responsible for relationship creation, so just setting the relation from inverse side will not result in the relationship being persisted in database via foreign key.




回答5:


Let me explain it this way: your question is reasonable and there is a clear answer - use load(). Why? In general we do have three ways how to obtain an instnace by ID.

1) One, extreme, and in fact inappropriate, mention just for complexity, would be to use a query, e.g. with restriction on ID. This query must hit DB...

2) Then, we have get(), which was intended as the most common way how to get item by ID. It always hits DB because its contract says (get):

Return the persistent instance of the given entity class with the given identifier, or null if there is no such persistent instance

So, to be sure that object exists or not, DB must be hit.

3) Finally, for a reason, there is a third contract - load(). It will never hit DB to check if there is such an item (with provided ID): load():

Return the persistent instance of the given entity class with the given identifier, assuming that the instance exists.

The Contract here expects that. On the other hand, this convention is there to help us to solve situation described in this query

If we do have reference ID, and we know that it does exist we shouuld use the load(). It will create a proxy instance - with provided ID and during the INSERT or UPDATE of that root/holder entity, the proxy ID will be used to create correct SQL Statement.

Summary: get() and load() are there for us for a reason. They were designed to support different scenarios. For CRUD operations of the root entity, we should recieve it by get(), to be sure that upper layers asked for existing ID. The use case for load() is when we do have ID and just want to persist that...

See also:

  • Different between session.get() and session.load()
  • NHibernate – The difference between Get, Load and querying by id


来源:https://stackoverflow.com/questions/23862969/hibernatedifference-between-setting-the-id-directly-in-the-bean-or-calling-the

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!