how to create a many to many relationships with core data? Swift, xcode - swift

I have 2 entities.
entity 1 - People
entity 2 - books
People entity has a property which is an array of string names of their favorite books.
I need to create a relationship that somehow maps the favorite book of a person to the corresponding book entity object(s).
I am not sure how to do this.
So far I have started by creating a relationship in core data model for people by setting destination to "books" and then for the books entity creating a relationship by setting destination to "people".
I don't see or understand how this will automatically pick out each of the person's favorite books...at the end of the day they are both seperate objects. How will the people class know that for a specific people instance that this, this and this book are that person's favorite?

Person attribute as array of string names of books -- very bad idea!
You need a to-many relationship with the Book entity. That's it.
Person <------------>> Book
Then, to get an array of book titles for a particular person:
(person.books as! Set<Book>).map { $0.title }
The person can have an additional to-one relationship (e.g. called favoriteBook) to one of the books.

Related

Core Data delete only the relationship link between Many-to-Many - not any objects

This is driving me nuts and I can't find anything where someone else has asked the same question. It can't be an unusual situation.
I have a Student entity and a Classes entity and both are bi-directional
Student<<-->>Classes
A Student can be assigned to many Classes and Classes can have many students
When a Student drops out of a given class, I want to remove the link between the particular student and the class - but without deleting either the student or the class objects.
All my attempts have deleted the student or the class object.
How do I remove the relationship without removing the objects ?
Thank You to Joakim Danielson ! The answer was there... I just wasn't aware... Core Data creates a func for the entity relationship.
As an example
entity Students has a relationship named Classes (destination = Classes entity)
entity Classes has a relationship named Students (destination = Students entity)
Core Data creates a func for each of the entity relationships:
.removeFromClasses()
.removeFromStudents()
these remove the relationship link from each of the respective relationships.
In order to remove the relationship completely, I execute both func - the entity objects both remain but are no longer linked !

CoreData One-to-One Relationship

In my app, Im using CoreData and I have two entities. VenueInfo and ContactInfo.
In the app, you can add venues, and each venue has ContactInfo. So I've setup a one to one relationship in my model.
So I would imagine, I could simply do the following:
[venue.contact setValue:textField.text forKey:email];
So like so you'd set the email attribute of the contact object which belongs to the venue. However this doesn't work.
Is it possible because the contact object doesn't exist yet?
The line you wrote won't work that way. I assume contact is the relationship name you have in your Venue entity in xCodeModel.
[venue.contact setValue:textField.text forKey:email]; // can't write this way..
Suppose your ContactInfo entity has two fields : phone, email so this way you can go.
and VenueInfo entity has two fields : name.
VenueInfo *venueInfo=[NSEntityDescription insertNewObjectForEntityForName:#"VenueInfo" inManagedObjectContext:self.managedObjectContext];
vanueInfo.name=txtVenueName.text; // venue name entry
ContactInfo *contactInfo=[NSEntityDescription insertNewObjectForEntityForName:#"ContactInfo" inManagedObjectContext:self.managedObjectContext];
contactInfo.phone=txtPhone.text;
contactInfo.email=txtEmail.text;
contactInfo.venue=venueInfo; // I assume venue is the relationship name you give in ContactInfo entity towards Venue entity.
What we did here is we saved phone and email details to ContactInfo entity only and then we just related it with currently selected VenueInfo accessing the relationship we declared in ContactInfo Entity for VenueInfo.
This maybe quite confusing so I'll recommend you to follow a few tutorials which will give you an idea to grasp some basics about core data relationships.

CoreData Relationship between entities and attributes

I'm having a little trouble grasping CoreData relationships, i'm note sure which relationship type I should be using between my 2 entities or if my logic is correct.
1) "Person" Entity - attributes such as name, tel, address, country, etc...
2) "CountryList" - attributes such as countryName, countryLat, countryLong, etc..
The CountryList entity is pre populated on first run of the app to include all the countries in the world and their respected data.
Where i'm stuck is do I need a relationship between these two entities?
I will be allowing the user to select a country from the CountryList entity data and wish to store there selection in the country attribute for Person entity.
Do I just take the countryName from CountryList as a string and store it in country from Person? or can I make a relationship between them?
I know a user can only belong to 1 country but a country can have lots of users so is this a one to many relationship? Or is it many to many because lots of users can belong to a country but a country can have loads of users? Confused!
Could someone please enlighten me on this and point me in the right direction in what i should be doing in xcode.
Many Thanks in Advance
Matt
EDIT: Is this correct?
I have made the changes to Entity names etc and think I now have the relationship set correctly.
EDIT 2: Removed country attribute and renamed relationships
Firstly, your "CountryList" entity should be called "Country", since it represents only one country. The fact that you have many of those countries has nothing to do with its name.
After that, it seems just natural to use a relationship, one "Person" has one "Country", but one country can have many persons. Therefore, one-to-many relationship. Using a relationship will simplify many operations you might want to perform (i.e. access all the country information of one person, or get a list of all persons being in one particular country).
Oh, and this might help you understand relationships a bit better: There are no "many-to-many" relationships in CoreData per se. You always define a relation from a source to a target. So if you define a relation from Country to Person, this will be a one-to-many relationship. One country, many persons. You can then define a relationship from Person to Country, which would be a one-to-one relationship. One person, one country. If you defined this as an one-to-many relationship, you would end up with a de facto many-to-many relationship (because on person can have many countries and one country can have many persons). It's not as complex as it appears.
Now, after you've defined your two relationships, you can set them as each others "Inverse Relationship". Do it for one of the relationships, the other one will be set automatically. After you did that, CoreData will for example update a Person's country when you add the person to the country's list.
See https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html for further information.
CountryList should just be Country
Then you set a 'many to one' relationship between Person.county and Country
You are using Core Data so you must define relationship between Person and Country if you want to fetch person's country from database.
And in this relationship you may take one to one relationship. As One person will belong to one country only. Of Course a country will have many person but unless you want to show all people related to particular country you do not need one to many relationship..
In case you want to implement one to many relationship this tutorial link maybe helpful to you for understanding one to many relationship..
http://www.theappcodeblog.com/2011/09/29/iphone-app-development-tutorial-core-data-part-2-one-to-many-relationship/

CoreData Guidance

So I have this problem I am trying to solve - I wonder if anyone can comment on/help me with the approach. The thing is, I have it partly solved, but with the rest I'm not quite sure.
Here's the deal:
I have a fairly large DB online which I want to load on first start of the App. After that I am only going to load it if new versions exist.
I use an xml parser to parse the data and enter all the data to my data model. The database consists of thousands of products, all described by various attributes.
Anyway, it's easy for me to save thousands of products in a database, then retrieving the data on demand.
I have a problem of how to categorize them and how to save the category data. There is a main category i.e. Hi-Fi which has several subcategories- let's say 'stereo', 'tuner', 'phone' and so on....
How to best save this info, that category a has 15 subcategories and each of these categories in turn has 30 products while securing performance and keeping process-time at a minimum. I don't want to check all 2000 Products whether I need to show them in a certain table view each time I open a new table view.
Any hints on the apporach are appreciated.
You'll need two entities: Product and Category.
Category has a to-many relationship called subcategories with a target entity of Category. The inverse relationship can be called parentCategory. Category also has a to-many relationship called products. Product would have an inverse relationship called category (or categories if a product can belong to multiple categories)
Now, you can get all the products for a given category by checking its products property. If you want to include all the products in the subcategories, you can do a fetch request with a predicate like this:
[NSPredicate predicateWithFormat:#"category == %# OR category IN %#", category, category.subcategories];
I think you can solve it by having a Core Data modal consisting of three entities: Product, Category and SubCategory.
Product has a relationship category with destination Category and a relationship subcategory with destination SubCategory.
Category has a to-many relationship products with destination Product and a to-many relationship subcategories with destination SubCategory.
SubCategory has a to-many relationship products with destination Product and a relationship category with destination Category.
When defining these relationships remember to assign the Inverse relationships as well.
Now you get a list of all products belonging to a specific category by just loading the Category in question and accessing the products property. It should also be possible to use NSFetchRequest for Product with a predicate specifying which category you want. Which is best regarding performance and memory requirements I can't say so you just have to test which approach works best.

LLBLGEN related array not populating in entity

i'm struggling with LLBLGEN and i guess ORM's in general.
i have created an entity, lets use a library example to explain:
i want to display a book object and also return a list of users who have loaned the book.
so i need to return the book object which contains a list of users.
DTO Book::
int bookId,
string bookName
additionally i wish to return with my book a collection of users who have loaned the book:
List<user> Loans
loans table might look like this:
int id
int userid
int bookid
currently my loans entity has now created this:
DTO Loans
int id
User user // user entity
Book book // book entity
im struggling to understand how this example would work in llblgen. can anyone assist with guidance or point me in the way of a tutorial?
at the moment, when i come up to update my model Book with a new loan associated to a book, im getting stackoverflow errors. i assume this is creating some sort of loop when attempting to update my Book object.
thanks
i noticed when running a profiler on SQL that the sql statement didnt include any join statements onto my relationship entities.
this was because my domain query didnt include prefetch items for my relationships, i added the following to my query:
var query = new DomainSearch<T>
{
SearchText = searchText,
PrefetchItems =
{
new Prefetch(typeof(Users))
}
};
To make sure, you are looking for a list of User entities that have loaned a particular Book entity. Is this the correct use case, or are you looking for a list of User entities that have borrowed the particular book?
Regardless, LLBLGen's support for these cases is great with referencing relationships between entities and using related entities quickly and easily.
Presuming you're looking up a book by unique BookId/ISBN/etc....
// Get the specific book entity
BookEntity book = new BookEntity(bookId);
foreach(UserEntity user in book.users)
{
// do stuff with list of users
}
It's just that simple assuming you've defined your relationships between entities.