Many to many relation in GvNIX - gvnix

In my E-R model I have two classes (User and Routine) related by many to many relationship, but I don't know how to translate it to GvNIX code.
Should I use a set attribute in each class specifying a many to many cardinality?
For example:
field set --fieldName routines --class ~.objects.User --type ~.objects.Routine --cardinality MANY_TO_MANY
field set --fieldName users --class ~.objects.Routine --type ~.objects.User --cardinality MANY_TO_MANY

To map a many-to-many relationship in both directions, one direction must be defined as the owner and the other must use the --mappedBy attribute to define its mapping.
Taking the typical Employee-Project example, one Employee can participate in many Projects and one Project can have many Employees. To create such bi-directional many-to-many relationships use the field set command:
Create the entities:
entity jpa --class ~.domain.Project
entity jpa --class ~.domain.Employee
Create the owner of the relationship:
field set --class ~.domain.Employee --fieldName projects --type ~.domain.Project
Then create the other side of the relationship:
field set --class ~.domain.Project --fieldName employees --type ~.domain.Employee --mappedBy projects
If the --mappedBy is not used, then the persistence provider will assume there are two independent relationships, and you will end up getting duplicate rows inserted into the join table. If you have a conceptual bi-directional relationship, but have two different join tables in the database, then you must not use the --mappedBy, as you need to maintain two independent tables.
Finally, to customize the generated code just use the JPA force Luke, take a look at http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany

Related

What's the benefit of `BelongsTo` relation?

What's the benefit of defining BelongsTo relation?
When I defined HasMany relation I could execute all my queries without missing anyone (I prefer to give me an example in case you find it's important to use BelongsTo relation).
The benefit is being able to flip the "base" and "child" in of the relation. LoopBack 4 relation filters are akin to an SQL LEFT JOIN, meaning that the filter must be scoped from the base model.
From the "Filtering by parent model" docs:
Where filters such as those used by model queries (create(), find(), replaceById(), and so on) cannot be used to filter a model by the value of its parent model. See its GitHub issue.
For example, we may have many Orders made by a Customer:
#hasMany(() => Order)
orders?: Order[];
This relation enables querying for "orders made by a customer" or "orders made by a list of filtered customers", but not the other way around; "the customer that made that order" or "the customers that made a list of filtered orders".
A Belongs To relation solves this by creating a key on the Order that references a Customer:
#belongsTo(() => Customer)
customerId: number;
This means that we can now query "which customer made that order" or "which customers made the filtered list of orders".
Another important factor is that a Has Many relation can't be made into a Strong Relation as ANSI SQL does not have a method of representing such relations. From the docs:
LoopBack 4 implements weak relations with #belongsTo(), #hasMany(), #hasOne(), etc. This means the constraints are enforced by LoopBack 4 itself, not the underlying database engine. This is useful for integrating cross-database relations, thereby allowing LoopBack 4 applications to partially take the role of a data lake.
However, this means that invalid data could be keyed in outside of the LoopBack 4 application. To resolve this issue, some LoopBack 4 connectors (such as PostgreSQL and MySQL) allow defining a foreign key constraint through the #model() decorator. Please consult the respective connector documentation to check for compatibility.
Emphasis in italics is mine on why these restrictions apply.

How to Add target NSManagedObject to another one with an inverse many-to-many Core Data relationship without duplicating target NSManagedObject?

I had encountered an issue one of my projects, I had spent dozen of hours to find the solution, I had made some progress, but still not getting what I would like to achieve ideally. I am still finding solutions myself now, while I would really appreciate anyone could share any insight for constructive solutions.
Issue:
How to add a target NSManagedObject from a master list as one object
of the references in another NSManagedObject with an inverse
many-to-many relationship between each NSManagedObject without
creating duplicate target NSManagedObject in the master list.
Note:
The following example used an analogy to the full data model graphs
to my real project. The analogy is what I can best describe the issue
I have, while the objects in the analogy do not fully share the same
name of the objects in the real project.
What I have now:
A master list of ingredient objects, which are unique among each
other.
A list of recipe objects, each of which would like to have different
ingredient objects to define the recipe object.
What do I want to achieve:
Ingredient objects can be inserted as multiple times into a single recipe object with each insert as unique count instead of making same ingredient being considered as one single count.
I did not want to duplicate each ingredient object inside of the
master list to be able to add multiple ingredients objects to each
recipe object or cross multiple recipe objects.
What I had tried:
Use Core Data to manage the ingredient and recipe as 2
NSManagedObjects.
Had created a relationship attributes called “allHostRecipes” on the ingredient managed object, and set it as “to-Many“ relationship to the recipe managed object
Had created a relationship attributes called “allUsedIngredients” on the recipe managed object, and set it as “to-Many“ relationship to the ingredient managed object.
These two relationships are set as “inverse”.
I had a Recipe Description View with a Table View that lists all the ingredients that are and will be included inside of the recipe.
I created another Ingredients Selection Table View that can be triggered in the recipe description view to pick each ingredient,which is going to be added into the recipe.
Each time when an ingredient is picked in the Ingredients Selection Table View, I call objectAtIndexPath(_:) on the NSFetchedResultsController that is for ingredients Table View from the ingredients’ master list to find the selected ingredient objects in its ManagedObjectContext.
Then I passed the selected ingredient managed object (SelectedIngredientManagedObject) back to Recipe Description View and called mutableSetValueForKey("allUsedIngredients").addObject(SelectedIngredientManagedObject) on the NSFetchedResultsController that is for fetching ingredients that is contained inside of a recipe object.
The “NSFetchedResultsController that is for ingredients Table View from the ingredients’ master list” and “NSFetchedResultsController that is for fetching ingredients that are contained inside of a recipe object” are separate instance variables in “Table Views of Recipe Description View” and “Ingredients Selection Table View”. But they referenced the same ManagedObjectContext.
What I had got now:
The selected ingredient managed object can be added to the recipe.
But, if I selected the same ingredient multiple times, it only get count once in the Table Views of Recipe Description View instead of showing multiple counts by each inserting, which is NOT what I want to achieve as described above.
My Question:
What should I do or adjust to achieve the functionalities that I had
to describe above?
What I think the directions to solve the issue:
What other things should I do when defining the “Many-to-Many”
relationship in Core Data model?
Does the fact that the “to-Many“ reference is using an NSSet cause the count issue?
Is it necessary to create multiple ManagedObjectContext to achieve the desired functionalities?
Should I clone the selected ingredient managed object as a new ingredient managed object? Which I had tried, and it will add duplicated ingredient to the ingredients’ master list. This is also NOT what I want. If I need to clone it, how can I make it right?
I really appreciate your time to view it, I am looking forward to having your insights. Thank you very much.
Regards,
Knight
You need to remodel the data slightly: Remove the many-many relationship from Recipe to Ingredient, and replace it with an intermediate entity (finding a good name is difficult, let's say RecipeIngredientDetails).
Create a one-many relationship from Recipe to RecipeIngredientDetails, say allUsedIngredientDetails, with inverse (to-one) recipe.
Likewise create a one-many relationship from Ingredient to RecipeIngredientDetails, say allHostRecipeDetails, with inverse (to-one) ingredient.
This addresses the problem with a direct many-many relationship, where each Recipe can be related to each Ingredient only once. (You are correct, this is in part a consequence of the relationships being modelled as Sets, which cannot have duplicate members). You have two options: you could just add multiple RecipeIngredientDetails objects, each related to the same Recipe and Ingredient pair. Each such object might represent a standard base quantity of the ingredient. Note that you could not have just one object for each Recipe/Ingredient pair, and try to add that object to the same Recipe multiple times: a given Recipe and a given RecipeIngredientDetails object can be related at most once.
But it might be better to add an attribute to the RecipeIngredientDetails, say quantity. You then only need a single such object for each Recipe/Ingredient pair, and can update the quantity attribute to reflect the amount of the ingredient that is appropriate for that recipe.
This is the approach mentioned in the CoreData Programming Guide section on Modeling a Relationship Based on Its Semantics:
For this sort of relationship, use an intermediate (join) entity. An advantage of the intermediate entity is that you can also use it to add more information to the relationship.
It is equivalent to adding a join table with foreign keys and additional columns to a SQL database. I'm not aware of any simpler way of achieving your objectives in CoreData - there is no way to directly add attributes to relationships.
Regarding the ordering issue that you mention in comments, you had added "a Double type attribute in the Entity to keep track of the order". If you have only two entities, and a many-many relationship, and you add the order attribute to the Ingredient then (for example) if "Flour" is the first ingredient for "Bread", it would have to be the first item for every other Recipe it is used in. In the approach I describe, you would add the attribute to the intermediate entity, RecipeIngredientDetails: the index (just as for the quantity) depends on both the recipe and the ingredient.
For indexes there is, however, another option I should mention: you could (in the data model editor) define the relationship from Recipe to RecipeIngredientDetails as ordered. The resulting property will be an ordered set (so you can insert, remove or move items to achieve the correct order).

Core Data: Cascading 1:1 Relationships

Scenario: Cascading 1:1 Relationship as shown below.
I merely want to have an inverse relationship amongst a few entities, based on the userID field.
Questions:
1) How does the relationships know which field to link to?
All I did was indicate target and give the relationship a distinct name.
If the relationship is independent on the supplied userID, then I assume such field is superfluous; correct?
2) You'll notice that I need two (2) relationships: userID & userID2.
Essentially I merely want to link all common userId values across files. Is this the correct setup?
Core Data isn't a relational database, therefore you don't need a specific field to create a relationship between objects.
Typically you use relationships to model what would be a property on an object.
If you want UserConfigurations, UserCredentials, etc. to be related to a User then you should create a relationship between User and each of the user specific objects.
Then you can access a users configuration somewhat like this:
user.configurations
If you have set up inverse relationships, which Core Data recommends, you can also access the User from the UserConfigurations object. That allows you to access other parts of the object graph easily, e.g. you could access a users events from a users configuration:
configuration.user.events
This way you don't need relationships between the different objects that are related to a user.
Your data model should look similar to this:

MagicalRecord - ManyToMany: Do I need to add entities on both sides of the relationship?

Let's say you have a many to many relationship between two entities and you use MagicalRecord to manually tie them together.
IE: A Vet has many Pets and a Pet has many Pets
In the code, do you need to add the entity on both sides of the relationship;
ie:
[vet1 addPetObject:cust1Pet1];
[vet1 addPetObject:cust1Pet2];
[vet1 addPetObject:cust1Pet3];
[cust1Pet1 addVetObject:vet1];
[cust1Pet2 addVetObject:vet1];
So, do I need to add the pet object to the vet, and then add the vet to the relevant pet object -- or will Core data / Magical record handle this relationship and tie them on both sides by itself?
Many thanks.
If the relationships are defined as inverse relationships of each other in the Core Data
model inspector then you need only set one of them. Core Data will automatically update
the inverse relationship. (This is in fact unrelated to MagicalRecord.)

Creating a glue table with Core Data?

Let's say I had one entity called "Garage" and one entity called "Cars".
In SQL I might create a third table (sometimes called a glue table) that would just have two fields "GarageID" "CarID"
That way I could relate certain cars to certain garages.
How would this be handled with the Core Data modeller?
Thanks!
You are talking about many-to-many relations. CoreData supports such model. Just create in both entities relations to each other set as "to-many". That's all.

Resources