Avoiding a fetch in a custom setter - core-data

I have two entities, Item and Category. Each item has one category, and a category can have 0-many items.
I have a special category, the misc category. I denote this with a boolean property, isMisc, so category.isMisc=YES.
When I delete a category, I want to reassign any of its items to the "misc" category. So I wrote the following custom setter for item:
- (void)setCategory:(Category *)category
{
[self willChangeValueForKey:#"category"];
if (category == nil) {
category = [Database theMiscCategory];
}
[self setPrimitiveValue:category forKey:#"category"];
[self didChangeValueForKey:#"category"];
}
The problem is, [Database theMiscCategory] performs a fetch, which I believe is discouraged. Is there another way to do this?
I have looked at just letting item.category = nil, but this introduces enough complications in other areas of the code that I'd much rather have a "misc" category.

You could create or fetch the "misc" category object once in your program, e.g. after creating the managed object context. Then your custom setter method can always use this instance.
If you work with several managed object contexts, then you would have to create one object for each context.

Related

How to fetch only immediate categories of a category in Hybris?

I only expect to fetch the direct children to the parent category. But instead I get all the children to that category by using getAllSubcategories method of DefaultCategoryService class.
Example: Say I have categories "Men" which has subcategories pants and tops. And tops has subcategories t-shirt and sweaters. Then when on the Men category I would expect to see only pants and tops. But what I am seeing in the latest hybris is all categories(pants, tops, t-shirt, sweaters etc. ) when clicking on Men.
Could someone please guide how to achieve that ? Or Do i need to write a flexible Query?
If you only want the direct children, you can make use of getCategories() on the category object model. This will only give you the direct children of that specific category
Where you are now calling getAllSubcategoriesForCategory(category), you can just go for category.getCategories()
Hi There is no OOB method to give you only immediate subcategories but yes we can use the above solution described by #Yoni
So you can create a simple method like this and use it when required.
#Override
public List<CategoryData> getSubCategories(final String categoryCode)
{
final CategoryModel category = defaultCategoryService.getCategoryForCode(categoryCode);
if (category == null)
{
return Collections.emptyList();
}
final Collection<CategoryModel> subCategories = category.getCategories();
return categoryConverter.convertAll(subCategories );
}

Serializing NSManagedObject

I'm using a category on NSManagedObject, called NSManagedObject+Serialization.h located here https://gist.github.com/nuthatch/5607405.
Everything pretty much works great, but I need to implement this but not sure how? I want to skip some objects.
- (NSDictionary*) toDictionary {
// Check to see there are any objects that should be skipped in the traversal.
// This method can be optionally implemented by NSManagedObject subclasses.
NSMutableSet *traversedObjects = nil;
if ([self respondsToSelector:#selector(serializationObjectsToSkip)]) {
traversedObjects = [self performSelector:#selector(serializationObjectsToSkip)];
}
return [self toDictionaryWithTraversalHistory:traversedObjects];
}
How do I add object relationships to be skipped?
Many Thanks
In your managed object subclass you must implement the serializationObjectsToSkip:
- (NSMutableSet*) serializationObjectsToSkip
{
NSMutableSet* objectsToSkip = [NSMutableSet new];
//Here you select objects that relate to this object and you don't want to serialise.
//Insert them into `objectsToSkip`
return objectsToSkip;
}
However, the implementation of the serialisation looks buggy (lines 80 and 93) ... (if you don't supply all objects to skip in advance)
The toDictionary of the relatedObject is skipped and so objects that the related objects may want to skip will not be added to the traversal history set ...
A quick fix might be to replace these lines with the full implementation of toDictionary and merging the traversal history set and the objectsToSkip sets returned ...
A better solution will be to change the signature of the toDictionary method to accept the traversal history and do the set merging there and replace the above lines with toDictionary of the related object.

Sorting NSFetchedResultsController using a to-many relationship property

SCENARIO
I have two entities: Item and ListDetail (which contains prices for different lists for every item). This is absolutely needed and I can't provide a price attribute for the Item entity because every item can have more prices for different dynamic lists (retail, b2b ecc.).
The relationship is:
Item (lists) <------->> (item) ListDetail
The current active list in my app change dinamically, so let's say I have an integer variable with the current active list: _ACTIVE_LIST_CODE_. When I need a price for an item object I use an helper method on the Item class:
-(NSNumber*) getPrice {
NSSet *lists=[self.lists filteredSetUsingPredicate: [NSPredicate predicateWithFormat:#"listId == %d",_ACTIVE_LIST_CODE_]];
ListDetail *activeList=[[lists allObjects] objectAtIndex:0];
return activeList.price;
}
THE PROBLEM
I use a UITableView with NSFetchedResultController in order to select and show some items for different sections. Nothing special. I would like to order the fetchedObjects using the items price for the active list. If price was an attribute of Item I would added simply a sort descriptor to the fetch request like so:
[NSSortDescriptor sortDescriptorWithKey:#"price" ascending:YES];
But as said before this is not possible, price is a dynamic attribute.
If using transient properties was possible for sort descriptors, I would set a price transient properties calculated on fly using my helper method. Nothing to do.
Using a keypath in the descriptor like "lists.price" is not possible (or maybe I don't know how to do that), just because it's a to-many relationship and it's modeled with a NSSet.
I tried some workaround, without success:
1) observing _ACTIVE_LIST_CODE_ changes to set items price in a non-transient attribute.
2) after the fetch request, before presenting the table view, reorder a brand new array with fetched objects using the transient "price" property, iterate the orderdered array following an ascending integer index "i" and assigning this value to a non-transient property "order" for the Item entity. Using "order" for sort descriptor in the fetch request. (This approach is described here: Re-ordering NSFetchedResultsController)
Both of them works, but they slow down performance because I have thousands of items in the fetch results... Any idea?
How about fetching ListDetail instead? You could restrict and sort with the appropriate predicates and sort descriptors, exactly as you propose.
fetchRequest.predicate =
[NSPredicate predicateWithFormat:#"listID = %#", activeListCode];
fetchRequest.sortDescriptors =
#[[NSSortDescriptor sortDescriptorWithKey:#"price" ascending:YES]];
Now, to group by some attribute of item should be simple and efficient because it is a to-one relationship. Your fetched results controller's sectionNameKeyPath can be something like
#"item.category"

Access detail element of a collection inside a section in openxava

How can I access the details element of a collection entity which is inside one section of another entity with openxava? For example, in the view of entity A, we have section {S1,S2,S3} and inside section S3 view, we have {collection of entity B}. Now I want to access the detail element of entity B, so that i can fill the element in an action controller. How do I do that?
Get the collection directly from the view, in this way:
Collection myCollection = getView().getSubview("myCollection").getCollectionObjects();
It must work even with oldest OpenXava versions
Obtain the entity associated to the view and get the collection from it. Since OpenXava 4.3 you can do it in this way:
MyEntity myEntity = (MyEntity) getView().getEntity();
Collection myCollection = myEntity.getMyCollection();
If you're using an OX previous to 4.3 do it in this way:
Map keyValues = getView().getKeyValuesWithValue();
if (!keyValues.isEmpty()) {
MyEntity myEntity = (MyEntity)
MapFacade.findEntity(getView().getModelName(), keyValues);
Collection myCollection = myEntity.getMyCollection();
}
You can do it in several ways. Here you have one, I have used it with some references that I want to modify from inside of an action called by the base module (which should work with your collection):
Query q = XPersistence.getManager().createQuery("JPQL QUERY TO RETRIVE THE COLLECTION WITH :parameterIfNeeded");
q.setParameter("parameterIfNeeded", "value");
List entityBList = q.getResultList();
if (getView().getModelName().equalsIgnoreCase("yourBaseModelViewName")) {
getView().getSubview("yourSubViewName").setModel(entityBList);
getView().getSubview("yourSubViewName").refresh();
}
You must to be using OX 4.6 to be able to use setModel(). And remember that the "yourSubViewName" is the name of the property for your collection into the base model.
I have not tested that code with a collection, so make the adjustments according to your needs, maybe you will need to CAST the query result list or something.

Core Data uniqueness

Is there any way I can validate a value updated in a Core Data entity's property against values of the property in other entities in the collection?
At the moment I create an entity with some default values, add it to arrangedObjects, then get the user to modify the various property values. However, I would like to check a particular property and make sure there're no other entities in the array with the same value for that property. What's the best way to do this?
Many thanks,
Dany.
Manually checking is only a few lines of code with a fast enumeration loop:
BOOL unique = YES;
for (NSManagedObject *obj in collection) {
if (obj.property == value) {
unique = NO;
break;
}
}

Resources