Delete() and Deleteall() in Hibernate - sql

Consider the below two methods to delete a Set of Employees with the name "John" .
List<Employee> list = new ArrayList<Employee>();
String query= " from Employee emp where emp.name = 'John'";
list=getHibernateTemplate().find(query);
First Method:
getHibernateTemplate().deleteAll(list);
Second Method:
Iterator<BulkChangeRequest> itList = list.iterator();
while(itList.hasNext()) {
Employee emp = itList.next();
getHibernateTemplate().delete(emp);
}
Do they differ significantly in terms of performance? Are both of them essentially the same i.e. does the deleteAll method delete row one by one?
Also wouldn't it be better to do it in SQL using the following query?
" delete from Employee where name = 'John'"

Yes. It would be better to use SQL or HQL to delete all employee records named 'John' rather then the first option. Simply because in first option, you have to load all employee record from db to delete. That's obviously an extra task.
I think, for delete() and deleteAll(), there will be no difference except in delete(), it will create new session for every call; whereas in deleteAll(), all objects will be deleted in one session. But the number of queries will be the same.

I suggest you read this section, one shot delete:
https://docs.jboss.org/hibernate/orm/3.5/reference/en/html/performance.html#performance-collections-oneshotdelete
Deleting collection elements one by one can sometimes be extremely
inefficient. Hibernate knows not to do that in the case of an
newly-empty collection (if you called list.clear(), for example). In
this case, Hibernate will issue a single DELETE.

Related

Spring bulk update fields with id's matching the given list

I need to do multiple updates in my DB based on the provided id.Right now I am iterating the id List and calling the update function of my repository again and again.However this is not efficient.I want to know if there is a way I can do bulk updates in one rest call by passing the id List and the other new field value list as parameter.Thanks in advance for the help.
Right now I'm calling this method again and again to update the values.However this is not at all efficient:
#Transactional
#Modifying
#Query("UPDATE Student c SET c.rollNo= :rollNo WHERE c.id = :id")
void updateStudentRollNo(#Param("id") long id, #Param("rollNo") String rollNo);
If you have the Student entities where you call the method updateStudentRollNo, you may call repository.saveAll(students) , that will make the updates on list. The way you are trying to do is not possible, because each student have a different rollNo, so batch update like that can't be done.

Simple.Data Eager Load SimpleQuery object

It appears that Simple.Data will lazy load by default.
I simply want Simple.Data to query the database and put the results in an object. For example, as soon as this piece of code is executed the results from the database should be stored in employeeData and the database should not be called again:
var employeeData = db.Employee.FindAllByEmployeeId(employeeId) .Where(db.Employee.EmployeeId == 1);
How do I do this? The Simple.Data documentation only describes how to eager load joins. I do not require any joins, simply to get results from a table when I choose to. If I include this WithEmployee() it will do a left join on the Employee table and output the same data twice...
Figured it out... turns out I can just create a list from the output which will save the data
eg.
.ToList<Employee>()

NHibernate Hanging on Lazy Loaded Query

First of all, I'm using Fluent NHibernate with LinqToNHibernate.
I've got a query to do a search on a table based on what data the user entered. So, for example, I'm doing something like this:
'build the initial query that we will filter--this is lazy loaded
Dim results As IEnumerable(Of Customers) = Me.GetCustomers()
'filter by owner name
If String.IsNullOrEmpty(OwnerName) = False Then
results = results.Where(Function(s) s.Name.Contains(OwnerName))
End If
'execute query
results = results.ToList()
So essentially I'm building a where statement on the sql statement if the user wants to search by name. I'm using all lazy configurations in my mappings, so the query shouldn't be retrieving the items until the "ToList()" is called. The problem is that NHibernate hangs on this statement. I thought at first it was because there were so many records in the db(about 500,000).
But I changed the line where I am filtering the results to this:
results = SessionFactoryProvider.SessionFactory.CurrentSession.Linq(Of Customer).Where(Function(c) c.Name.Contains(OwnerName))
And it works very quickly. But I can't seem to figure out why. Any ideas?
In the first case you are retrieving all the records and using Linq-to-objects to filter that list.
In the second case, you are sending the query to the database (NHibernate.Linq converts your expression into a SQL WHERE clause).
Now, I don't know what is the return type of GetCustomers, but since you're storing it into an IEnumerable(Of Customer), .NET has no way of knowing about an underlying provider. If GetCustomers' code is something like:
Return CurrentSession.Linq(Of Customer)
...Then the problem is with that conversion. Just change the first line to:
Dim results As IQueryable(Of Customers) = Me.GetCustomers()

Table not getting updated while using LinQ

I am trying to update a table using LinQ. Though records are getting inserted, for some reason they are not getting updated.
what can be possible problem
Dim db as new empDataContext
Dim emptable as new employee
if update then
emptable=GetEmp(txtempID.Text)
emptable.Name="Test"
emptable.Age=11
emptable.City="NYC"
else
emptable.Name="Test"
emptable.Age=11
emptable.City="NYC"
emtable.deptID=10
db.employee.InsertOnSubmit(emptable)
end if
db.SubmitChanges()
Judging just from what I can see here, I'm guessing your GetEmp method is using a different data context to retreive the data than the one you're using to save it back to the DB.
When using LINQ to SQL, the context is what tracks the changes to the tables. If you're not careful and mix Contexts by accident, you can get strange behaviors like this.
You can test by chaging:
emptable=GetEmp(txtempID.Text)
to
// Returns the first matching employee with the id
emptable = (from e in db.Employees
where e.id == txtempid.Text).FirstOrDefault()
If you find that the context is the issue, just modify your GetEmp method to accept the context as a parameter rather than creating a new one itself.
What does GetEmp do? In particular, as presented it appears that it does not have a reference to the empDataContext named db. DataContexts are examples of identity maps and as such they track items that have been loaded from a persistence mechanism. If you are using a different DataContext in GetEmp then the DataContext db does not know about the instance of employee with SomeID equal to the value represented by txtempID.Text.
So either pass a reference to db into GetEmp or change your code to the following:
emptable = db.Single(Function(e as employee) e.SomeID=Int32.Parse(txtempID.Text))
then your update should work.
If I had to guess, I would say that the GetEmp() call is not using the same database context object. Therefore, Linq-To-SQL doesn't think any changes are occuring in the "db" database context.
Randy

In a datacontext are inserted values not available within the datacontext until after submitchanges?

I'm going through an XML file of articles and the journalist(s) that wrote them. As we are adding the articles into _Data our datacontext we may come across a journalist that needs adding so we do this:
newJourno = New journalist With {.name = strJournalist}
_Data.journalists.InsertOnSubmit(newJourno)
.articles_journalists.Add(New articles_journalist With {.id_journalist = newJourno.id, .id_article = .id})
However subsequently we may come across this same journalist again and nothing is returned when we do this:
Dim journo = _Data.journalists.Where(Function(s) s.name = strJournalist).SingleOrDefault
So it uses the code above again to insert the same journalist again.
Once all of our inserts are done we do a submitchanges. At this point it has a head fit:
INSERT statement conflicted with COLUMN FOREIGN KEY constraint 'FK_articles_journalists_journalists'. The conflict occurred in database 'blah', table 'journalists', column 'id'. The statement has been terminated.
From looking through the sql generated in sql profiler you can see that it is trying to add some journalists more than once, this will fail as the name must be distinct. The subsequent records that are trying to be inserted with these journalists are failing as the journalist wasn't updated.
Surely if I have a collection of journalists, add some to it and then look in my collection I should see all of them and not just the original ones. I can fudge it I guess by doing a submitchanges but that seems a bit silly.
Thanks in advance,
Dave.
If you want to add two child-parent rows to the database, you must assign the entity, instead of the Id column, the Id will be autogenerated and will be available only after the submit changes.
You have to do a articles_journalist object, and then assign the newJourno entity to this:
articles_journalist.journalist = newJourno;
CMS is right about needing to assign the object, not the id.
However this doesn't seem to get around the problem of the datacontext not realising that it has had new stuff added to it until you submitchanges. I can only presume this is by design and therefore I am now calling submitchanges as and when the code inserts objects that we later search for.
"the name must be distinct."
This is a serious design flaw. Person names are never unique.