Iterator.remove()
is safe, you can use it like this:
List<String> list = new ArrayList<>();
// This is a clever way to create the iterator and call iterator.hasNext() like
// you would do in a while-loop. It would be the same as doing:
// Iterator<String> iterator = list.iterator();
// while (iterator.hasNext()) {
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
if (string.isEmpty()) {
// Remove the current element from the iterator and the list.
iterator.remove();
}
}
Note that Iterator.remove()
is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.
Source: docs.oracle > The Collection Interface
And similarly, if you have a ListIterator
and want to add items, you can use ListIterator#add
, for the same reason you can use Iterator#remove
— it's designed to allow it.
In your case you tried to remove from a list, but the same restriction applies if trying to put
into a Map
while iterating its content.
if you want to filter the collection on demand, using a filter is a valid choice.
You would need to declare the filter on both the Version class and in the bag element and apply the filter from the NHibernateSession.EnableFilter method
if you always want to fetch a single Version in the bag then implement a 'where' in the mapping of the bag:
<bag name="Versions" cascade="all-delete-orphan" inverse="true" lazy="false" where="CurrentVersionNumber = Versions.VersionNumber" >
<key column="DataObjectId" />
<one-to-many class="DataObjectVersion" />
</bag>
note that in the 'where' you write proper SQL not HQL and as such the proper SQL i write above probably has to be changed to reflect your schema
Additionally if a single object is to be fetched setting up a bag and the according IList may be an overkill.
Applying a formula property and a DataObjectVersion object in the class may be more appropriate
in the class DataObject replace the IList with
public virtual DataObjectVersion Version { get; set; }
and in the mapping replace the 'bag' with something in the lines of
<property name="Version" type="DataObjectVersion" update="false" insert="false" formula="(select v.DataObjectVersionId, v.Comments, v.VersionNumber, v.DataObjectId from DataObjectVersion v where v.VersionNumber = CurrentVersionNumber)" />
again only proper SQL is allowed
i've used computed properties with native datatypes (datetime, string etc) and fetching an Entity may (or may not) need something more or different
Last but not least, you could apply a filter on the collection after you have fetched the primary object DataObject by creating a filter on the collection
IList<DataObjectVersion> fVersion =
NHibernateSession.CreateFilter(do.Versions, "where VersionNumber = :ver")
.SetParameter("ver", do.CurrentVersionNumber)
.List<DataObjectVersion>();
where the do.Versions collection is not initialized, only the results fetched in the separate fVersion collection and this is a second SELECT after already having made the round-trip to the db for the DataObject fetch.
Best Answer
I ran into this issue and I used Linq to get around it.
I BELIEVE that's the syntax, if someone could verify that would be great I haven't used LINQ too much.