use NSPredicate to strip ToMany relationships on coredata - core-data

I have a coredata table with a list of 32 languages. Each language has a relationship one-to-many with translations, which contains 32 translations of the associated language.
For example English would be:
Language.code = #"EN";
//english translation
Language.Translation.code = #"EN";
Language.Translation.text = #"english";
//italian translation
Language.Translation.code = #"IT";
Language.Translation.text = #"inglese";
...
End French would be:
Language.code = #"FR";
//english translation
Language.Translation.code = #"EN";
Language.Translation.text = #"french";
//italian translation
Language.Translation.code = #"IT";
Language.Translation.text = #"francese";
...
And so on to form a matrix of 32x32.
I use this through out my app but at some point I need to show a tableview with each language in his own let's say idiom (english, français, italiano, español, 日本人, ...).
To do this I did use the usual NSFetchRequest and then on tableview cellForRowAtIndexPath: I run an NSPredicate like:
#"Language.code = Language.Translation.code"
The result is quite memory wasting, so I was wondering if there is a way to strip the 31 translations in the relationship I do not use while I am doing the NSFetchRequest.
I tryed something like:
#"ANY LangTranslations.translationCode = code"
but this is not stripping, it's just checking!
Is there a better way to do it?

It sounds like you have a datamodel something like this:
Language{
code:string
translations<-->>Translation.language
}
Translation{
code:string
text:string
language<<-->Language.translations
}
If you already have the Language object, then you don't have to fetch the related Translation objects you just have to walk the relationship. For any particular Language object, the value of translations will return a NSSet of all the related translations. Once you have the set, you can sort it into an array for display in a tableview.
Update:
From comment:
Basically I would like to retrieve each Language object with only one translation out of the 32 it has.
Core Data doesn't work like that. A fetch returns instances of one entity and then you walk that entities relationships to find other instances of related entities. However, you need to be clear on what object you really want. In this case do you want a Language object with certain Translations object/s or do you want a Translations object with a specific Language object?
If the former, the first step is to fetch the Language object you want with a predicate of:
NSPredicate *p=[NSPredicate predicateWithFormat:#"code=%#",languageCode];
... that will give you the english Language object. Then you just ask the Language for the appropriate Translation object:
NSPredicate *p=[NSPredicate predicateWithFormat:#"code=%#",languageCode];
Translation *t=[[aLanguageObj.translations filteredSetUsingPredicate:p] anyObject];
If you have to do this a lot and you have NSManagedObject subclasses for Language and Translation, you could warp the previous code up in a method on the Language class that would handle this for you:
-(Translation *) translationForCode:(NSString *) languageCode;
... and uses it like:
cell.textLabel.text=[[aLanguageObj translationForCode:languageCode].text];
If you want a Translation object related to a specific Language object, then you would run a fetch on the Translationentity with a predicate like:
NSPredicate *p=[NSPredicate predicateWithFormat:#"code==%# AND langauge.text==%#",codeForTranslation,languageCode];

Related

My segmented picker has normal Int values as tags, How is this passed to and from CoreData?

My SwiftUI segmented control picker uses plain Int ".tag(1)" etc values for its selection.
CoreData only has Int16, Int32 & Int64 options to choose from, and with any of those options it seems my picker selection and CoreData refuse to talk to each other.
How is this (??simple??) task achieved please?
I've tried every numeric based option within CoreData including Int16-64, doubles and floats, all of them break my code or simply just don't work.
Picker(selection: $addDogVM.gender, label: Text("Gender?")) {
Text("Boy ♂").tag(1)
Text("?").tag(2)
Text("Girl ♀").tag(3)
}
I expected any of the 3 CoreData Int options to work out of the box, and to be compatible with the (standard) Int used by the picker.
Each element of a segmented control is represented by an index of type Int, and this index therefore commences at 0.
So using your example of a segmented control with three segments (for example: Boy ♂, ?, Girl ♀), each segment is represented by three indexes 0, 1 & 2.
If the user selects the segmented control that represents Girl ♀, then...
segmentedControl.selectedSegmentIndex = 2
When storing a value using Core Data framework, that is to be represented as a segmented control index in the UI, I therefore always commence with 0.
Everything you read from this point onwards is programmer preference - that is and to be clear - there are a number of ways to achieve the same outcome and you should choose one that best suits you and your coding style. Note also that this can be confusing for a newcomer, so I would encourage patience. My only advice, keep things as simple as possible until you've tested and debugged and tested enough to understand the differences.
So to continue:
The Apple Documentation states that...
...on 64-bit platforms, Int is the same size as Int64.
So in the Core Data model editor (.xcdatamodeld file), I choose to apply an Integer 64 attribute type for any value that will be used as an Int in my code.
Also, somewhere, some time ago, I read that if there is no reason to use Integer 16 or Integer 32, then default to the use of Integer 64 in object model graph. (I assume Integer 16 or Integer 32 are kept for backward compatibility.) If I find that reference I'll link it here.
I could write about the use of scalar attribute types here and manually writing your managed object subclass/es by selecting in the attribute inspector Class Codegen = Manual/None, but honestly I have decided such added detail will only complicate matters.
So your "automatically generated by Core Data" managed object subclass/es (NSManagedObject) will use the optional NSNumber? wrapper...
You will therefore need to convert your persisted/saved data in your code.
I do this in two places... when I access the data and when I persist the data.
(Noting I assume your entity is of type Dog and an instance exists of dog i.e. let dog = Dog())
// access
tempGender = dog.gender as? Int
// save
dog.gender = tempGender as NSNumber?
In between, I use a "temp" var property of type Int to work with the segmented control.
// temporary property to use with segmented control
private var tempGender: Int?
UPDATE
I do the last part a little differently now...
Rather than convert the data in code, I made a simple extension to my managed object subclass to execute the conversion. So rather than accessing the Core Data attribute directly and manipulating the data in code, now I instead use this convenience var.
extension Dog {
var genderAsInt: Int {
get {
guard let gender = self.gender else { return 0 }
return Int(truncating: gender)
}
set {
self.gender = NSNumber(value: newValue)
}
}
}
Your picker code...
Picker(selection: $addDogVM.genderAsInt, label: Text("Gender?")) {
Text("Boy ♂").tag(0)
Text("?").tag(1)
Text("Girl ♀").tag(2)
}
Any questions, ask in the comments.

Core Data - NSFetchRequestResult: count of items in one-to-many relationship from result?

Consider a Core Data model with two Entities: TermDictionary and Term. The TermDictionary has a "name" property, and a one-to-many relationship called "terms" which points to a set of Term objects, each of which consists of two properties: "name" and "score".
I've got an NSFetchRequest which I'm using as a data source for a UITableView which displays all of the TermDictionaries in the database. The idea is that the table will, for each cell, display the name of the dictionary, along with a count of the number of terms in that dictionary.
In the following code snippet, item contains an NSFetchRequestResult for the "TermDictionary" entity:
let thisDict = item as! TermDictionary
cell.textLabel?.text = thisDict.name
cell.detailTextLabel?.text = "\(thisDict.terms?.count ?? 0) terms"
...The table cells are correctly displaying the names of the Term Dictionaries, however it looks like thisDict.terms is always coming up nil, so the number-of-terms label always shows zero.
Do I need do do something special with item rather than just casting it to my TermDictionary managed object subclass?
You do not need to do anything special. If thisDict.terms prints as nil, it really is nil. Check your data store.

How to get many to many values and store in an array or list in python +django

Ok
i have this class in my model :
i want to get the agencys value which is a many to many on this class and store them in a list or array . Agency which store agency_id with the id of my class on a seprate table.
Agency has it's own tabel as well
class GPSpecial(BaseModel):
hotel = models.ForeignKey('Hotel')
rooms = models.ManyToManyField('Room')
agencys = models.ManyToManyField('Agency')
You can make it a bit more compact by using the flat=True parameter:
agencys_spe = list(GPSpecial.objects.values_list('agencys', flat=True))
The list(..) part is not necessary: without it, you have a QuerySet that contains the ids, and the query is postponed. By using list(..) we force the data into a list (and the query is executed).
It is possible that multiple GPSpecial objects have a common Agency, in that case it will be repeated. We can use the .distinct() function to prevent that:
agencys_spe = list(GPSpecial.objects.values_list('agencys', flat=True).distinct())
If you are however interested in the Agency objects, for example of GPSpecials that satisfy a certain predicate, you better query the Agency objects directly, like for example:
agencies = Agency.objects.filter(gpspecial__is_active=True).distinct()
will produce all Agency objects for which a GPSpecial object exists where is_active is set to True.
I think i found the answer to my question:
agencys_sp = GPSpecial.objects.filter(agencys=32,is_active=True).values_list('agencys')
agencys_spe = [i[0] for i in agencys_sp]

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.

What is the correct way for quering a NSNumber in a NSArray within CoreData?

I have a Entity with a column of type ID named "responsibleUsers". In this column I store an Array containing NSNumbers.
I want to fetch all objects of this entity, that match my current User. Therefore i create following predicate:
[NSPredicate predicateWithFormat: #"%# IN responsibleUsers",[NSNumber numberWithInteger: curUser.oID.integerValue] ]
whatever I try, my App crashes. Once with a EXC_BAD_ACESS, once with "unimplemented SQL generation for predicate nsnumber"
What is the correct way to query my entity?
The query you are trying assumes that you have two entities: the entity you querying (let's call it Group) and another one, perhaps called User, which is set up as a to-many relationship from Group called responsibleUsers. You would then be able to use the predicate you suggest:
[NSPredicate predicateWithFormat:#"%# IN responsibleUsers, aUser];
This would be the recommended use of Core Data object graphs.
In your setup, it seems you have an array of NSNumber set as a property rather than a relationship. Therefore you cannot use such a query. You simply have to retrieve the array and query the array.
BOOL containsResponsibleUser = NO;
for (NSNumber *n in aGroup.responsibleUsers) {
if ([n isEqualTo:[NSNumber numberWithInteger: curUser.oID.integerValue]])
containsResponsibleUser = YES;
}
If you are indeed querying something like a group of users, I would recommend the first approach. If you are querying some kind of user, I would suggest a BOOL property responsible as the most efficient solution.

Resources