Why in JPA EntityManager queries throw NoResultException but find does not? - jpa

Can somebody tell me the intrinsic reasons why in the JPA 1.0 EntityManager when retrieving an Object via find, you have to deal with null if not found, but when using the Query interface via createQuery getResultList throws a NoResultException when not found.
Maybe i am missing something but I feel its very inconsistent for a Language, and actually I had to do a lot of redesing because of changing from a simple finder to a more fine grained query using the query interface.
Thanks guys.

Queries can be used to retrieve almost anything including the value of a single column in a single row.
If getSingleResult() would return null, you could not tell whether the query did not match any row or whether the query matched a row but the selected column contains null as its value.

When you do a find, jpa will use the primary key to locate the entity object, often using second level cache and it is typically much faster than createQuery and getSingleResult.
You either get null or the Object back from find. When you do a createQuery and instance of Query object is created. If you do a getResultList it will not throw a NoResultException, only if you do a getSingleResult will it throw that exception. If you do a getResultList and none is found, then null will be returned.

Also, NoResultException will mark the transaction rolledback in weblogic 10.3.2.
See this article: NoResultException marks transaction rollback

I think it eliminates this null check :
Object o = q.getSingleResult();
if (o != null)
return (MyObj) o;
return o;
By introducing a RuntimeException (NoResultException) , programmers can safely cast q.getSingleResult() to MyObj , and leave the exception to the caller.
As to q.getResultList() , it will always return a list , null-check is not necessary.
But I still feel this non-intuitive.

Related

Best practise for inserting records with slick 3.x

Can someone tell me what the best practice is for inserting records with slick 3.x?
I want a simple pattern of insert a record, and the response should be the model with the updating primary key value.
case class User(int: Int, name: String, email: String)
I want to do the following:
Insert a new record
Return the model (User) with the updating PK value for the id property
Throw an exception if the insert failed, which I believe is when the insert returns less than 0 right?
I am using postgresql if that matters.
The docs have this:
val userWithId =
(users returning users.map(_.id)
into ((user,id) => user.copy(id=Some(id)))
) += User(None, "Stefan", "Zeiger")
Is there a helper function that I could use in my entire DB layer that will also return an exception if the insert failed? i.e. if it is successful, return the user with Id otherwise throw an exception.
As #Laurece Bird mentioned, there's an answer already. Despite the fact that is aimed to slick 2.x, it should work on slick 3.x
Have you tried? Are you having any error?
Still, the logic it's the same, try returning something, and embrace the method on a java try/catch or in a scala Try

Doubt regarding JPA namedquery

I am trying to execute a namedquery
#NamedQuery(name="getEmployeeDetails",query="select e.username,e.email,e.image,e.firstname,e.lastname from Employee e where e.empid=?1")
Now when I execute this query in a EJB 3.0 Session Bean what is the object I should return.I tried returning Listits returning a Vector which creates a classcast exception.The employee table contains fields like password and other confidential details which I don't want to fetch.So I am not using select e from Employee e.
I am learning JPA can anyone help.
Below is the sample query which fetches only the required fields, but have to make such constructor for it.
Query : SELECT NEW package_name.Employee(e.username,e.email,e.image,e.firstname,e.lastname) FROM Employee e where e.empid=?1;
It will return Employee entity with selected fields & remaining will have default values.
Inspect the returned type by calling .getClass() on a returned object. I'd guess it's an array.
But this is not really a good way to use JPA. Select the whole entity and then just don't use what you don't need. It's not such a performance hit.

GUID or int entity key with SQL Compact/EF4?

This is a follow-up to an earlier question I posted on EF4 entity keys with SQL Compact. SQL Compact doesn't allow server-generated identity keys, so I am left with creating my own keys as objects are added to the ObjectContext. My first choice would be an integer key, and the previous answer linked to a blog post that shows an extension method that uses the Max operator with a selector expression to find the next available key:
public static TResult NextId<TSource, TResult>(this ObjectSet<TSource> table, Expression<Func<TSource, TResult>> selector)
where TSource : class
{
TResult lastId = table.Any() ? table.Max(selector) : default(TResult);
if (lastId is int)
{
lastId = (TResult)(object)(((int)(object)lastId) + 1);
}
return lastId;
}
Here's my take on the extension method: It will work fine if the ObjectContext that I am working with has an unfiltered entity set. In that case, the ObjectContext will contain all rows from the data table, and I will get an accurate result. But if the entity set is the result of a query filter, the method will return the last entity key in the filtered entity set, which will not necessarily be the last key in the data table. So I think the extension method won't really work.
At this point, the obvious solution seems to be to simply use a GUID as the entity key. That way, I only need to call Guid.NewGuid() method to set the ID property before I add a new entity to my ObjectContext.
Here is my question: Is there a simple way of getting the last primary key in the data store from EF4 (without having to create a second ObjectContext for that purpose)? Any other reason not to take the easy way out and simply use a GUID? Thanks for your help.
I ended up going with a GUID.
The size/performance issues aren't
critical (or even noticeable) with SQL Compact, since
it is a local, single-user system.
It's not like the app will be
managing an airline reservation
system.
And at least at this point, there
seems to be no way around the "no
server-generated keys" limitation of
the SQL Compact/EF4 stack. If someone has a clever hack, I'm still open to it.
That doesn't mean I would take the same approach in SQL Server or SQL Express. I still have a definite preference for integer keys, and SQL Compact's bigger siblings allow them in conjunction with EF4.
Use a Guid. AutoIncrement is not supported on Compact Framework with Entity Framework.
Also, if you ever want to create a application which uses multiple data sources, int PK's are going to fall apart on you very, very quickly.
With Guid's, you can juse call Guid.NewGuid() to get a new key.
With int's, you have to hit the database to get a valid key.
If you store data in multiple databases, int PK's will cause conflicts.
What I've done for SQL CE before, and I assume we have a single application accessing the database, is to calculate the MAX value on startup and put it in a static variable. You can now hand out sequential values easily and you can make the code to generate them thread safe very easily.
One reason to avoid Guids would be size = memory and storage space consumption.
You could also query SQL Compact metadata like so:
SELECT AUTOINC_NEXT FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Categories' AND AUTOINC_NEXT IS NOT NULL

MVC 1.0 + EF: Does db.EntitySet.where(something) still return all rows in table?

In a repository, I do this:
public AgenciesDonor FindPrimary(Guid donorId) {
return db.AgenciesDonorSet.Include("DonorPanels").Include("PriceAdjustments").Include("Donors").First(x => x.Donors.DonorId == donorId && x.IsPrimary);
}
then down in another method in the same repository, this:
AgenciesDonor oldPrimary = this.FindPrimary(donorId);
In the debugger, the resultsview shows all records in that table, but:
oldPrimary.Count();
is 1 (which it should be).
Why am I seeing all table entries retrieved, and not just 1? I thought row filtering was done in the DB.
If db.EntitySet really does fetch everything to the client, what's the right way to keep the client data-lite using EF? Fetching all rows won't scale for what I'm doing.
You will see everything if you hover over the AgenciesDonorSet because LINQ to Entities (or SQL) uses delayed execution. When the query is actually executed, it is just retrieving the count.
If you want to view the SQL being generated for any query, you can add this bit of code:
var query = queryObj as ObjectQuery; //assign your query to queryObj rather than returning it immediately
if (query != null)
{
System.Diagnostics.Trace.WriteLine(context);
System.Diagnostics.Trace.WriteLine(query.ToTraceString());
}
Entity Set does not implement IQueryable, so the extension methods that you're using are IEnumerable extension methods. See here:
http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/121ec4e8-ce40-49e0-b715-75a5bd0063dc/
I agree that this is stupid, and I'm surprised that more people haven't complained about it. The official reason:
The design reason for not making
EntitySet IQueryable is because
there's not a clean way to reconcile
Add\Remove on EntitySet with
IQueryable's filtering and
transformation ability.

JPA getSingleResult() did not receive any entities error

I'm writing updates as part of CRUD testing and when I test my code, I get an error saying no entities are found. I have no idea why, because my partner did the exact same code and he worked perfectly. Neither of us is able to figure out what's going on. I'm getting an error on the getSingleResult() method.
#Test
public void updateBookTest() {
Book book = em.createQuery("select b from Book b where b.title = :title", Book.class).setParameter("title", "createABook").getSingleResult();
tx.begin();
book.setTitle("updatedThisBook");
book.setAuthor("newAuthor");
tx.commit();
Book updatedBook = em.find(Book.class, book.getBookId());
assertEquals(book.getTitle(), updatedBook.getTitle());
assertEquals(book.getAuthor(), updatedBook.getAuthor());
System.out.println("updateBookTest:\t" + book.toString());
tx.begin();
book.setTitle("createABook");
tx.commit();
}
This is my code. Let me know if more information is needed.
getSingleResult must to throw a NoResultException if there is no result.
So, your test is Ok.
Check that both are using same database (and there is no data returned), both are running same query, and both are using same jpa implementation versions.
From javadoc (since jpa 1.0):
getSingleResult
java.lang.Object getSingleResult(): Execute a SELECT query that returns a single untyped result.
Returns: the result
Throws:
NoResultException - if there is no result
NonUniqueResultException - if more than one result
IllegalStateException - if called for a Java Persistence query language UPDATE or DELETE statement
QueryTimeoutException - if the query execution exceeds the query timeout value set and only the statement is rolled back
TransactionRequiredException - if a lock mode has been set and there is no transaction
PessimisticLockException - if pessimistic locking fails and the transaction is rolled back
LockTimeoutException - if pessimistic locking fails and only the statement is rolled back
PersistenceException - if the query execution exceeds the query timeout value set and the transaction is rolled back
Reference javadoc getSingleResult
Another point, check that your friend is not calling getResultList instead of getSingleResult. This method returns a list and no throw an exception if empty.
Reference javadoc getResultList