I have been learning to use Django over the last year and Python is not my native programming language. Normally, when I want to create a many to many relationship, I would create 3 tables, one of which contained two foreign keys to each of the other two tables. For this reason, I find the Django manytomany field very unnatural. Does this many to many field create a third table in the database to store the relationship ? If this is the case, then using a many to many field will stop the class structure from directly representing the table structure.
What I am wondering is if there is a reason I should be using this manytomany field or could I get away with using 3 classes to represent a many to many relationship ?
Thanks
Mark
I would create 3 tables, one of which contained two foreign keys to each of the other two tables. For this reason, I find the Django manytomany field very unnatural.
This is exactly what Django is doing behind the curtains. If you inspect the database, you will see a junction table [wiki]. Django simply does this in the background. It simply presents it to the foreground as a field. As you can see in the database Representation of the ManyToManyField:
Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship. By default, this table name is generated using the name of the many-to-many field and the name of the table for the model that contains it. Since some databases don’t support table names above a certain length, these table names will be automatically truncated and a uniqueness hash will be used, e.g. author_books_9cdf. You can manually provide the name of the join table using the db_table option.
You can even add extra fields to this junction table, by defining the model in between explicitly, and specify this in the through=… parameter [Django-doc]. For example:
class Category(models.Model):
name = models.CharField(
max_length=128,
unique=True
)
class Item(models.Model):
name = models.CharField(
max_length=128,
unique=True
)
categories = models.ManyToManyField(
Category,
through='ItemCategory'
related_name='items'
)
class ItemCategory(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
validated = models.BooleanField(default=False)
A ManyToManyField is thus more a concept to make representing and querying more convenient.
Related
In a scenario where we have a many-to-many relationship, what would be the ideal thing to implement an endpoint where you can get the data registered specifically for user X? For example, a class having multiple teachers and a teacher having multiple classes.
I'm using typeorm to make the relations. But on the front end, I have a screen that I need to get all the classes.
That's why I thought of putting the array of classes in the teachers table, because if I implement only the endpoint to get all the classes, I will actually get all the classes, instead of just the classes registered for the user. Or do relationships already solve this problem?
In addition to the specific classes for each teacher, I need to get some data that is in the class. Like name, number of students, etc.
It's quite simple, the best solution would be to put an array of classes in your teacher table. Then they could consume this endpoint to consume the class data.
You need a intermediated table, witch will have the Id of the Teacher (Primary Key of the Teachers table) and the Id of the Class (Primary Key of the Class table).
This way you can know witch or how many class the teacher (ID) have and the same for direction, how many teachers have the class (ID) by query to this table
Example:
Table Teacher:
Id
Name
1
Mary
Table Class
Id
Name
1
Math
2
Geo
Table TeachersClass
Id
TeacherId
ClassId
1
1
1
1
1
2
To know the teacher Mary class:
$ Select * From TeachersClass Where TeacherId = 1
And at the end, with the Class Id you get all information you need from the class table.
I have a very centralized table "RecordInfo" which holds some general data
e.g.: UserModified, UserCreated, DateTimeCreated, etc.
This table should be accessible via a navigation property from any other table in my application. Therefore I'm using a GUID Column to join the tables.
So it acts similar an one-to-one relation, but I cannot make a Foreign Key to multiple target tables. This will not work due to the FK constraints.
So I'm searching for a solution to implement navigation properties, without defining a ForeignKey - is this possible in any way?
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).
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:
I have read many about how to configure many to many realtionships with EF Code First and fluent configuration. But I couldn't understand why I should create an extra entity for the junction table. Lets assume that I have the following entities:
Department
----------
Id
Name
Material
----------
Id
Name
Now I want to keep records of materials for each department. So I need
DepartmentMaterial
-------------------
DepartmentId
MaterialId
Quantity
What I have read so far I need 3 entities: Department, Material and DepartmentMaterial. So actually I am mapping each table to a corresponding entity which was not I intended to do when I started to learn about DDD. I assumed that EF is going to map that junction table automatically and also queries about material quantities can be done over Department.
Hence, is it possible in EF Code First to configure fluently such a relation without an extra entity?
The junction table can stay out of the conceptual model (class model) if it's only got two foreign keys (DepartmentId, MaterialId). You want to record some data about the association. That's OK, the quantity belongs there. A department has quantity x of material y. Saying that a department has a quantity is meaningless.
This is not against DDD principles. The association class is a first-class citizen in the class model. It could even have its own behavior (like limiting quantities for certain department/material combinations).
This means that your model will not contain a many-to-many association but Department 1-n DepartmentMaterial n-1 Material. And you'll have to query materials of departments through the junction table. This is a very common situation. I hardly ever see pure junction tables in real life. They're collector's items.
Example query:
var query = from d in db.Departments
from dm in d.DepartmentMaterials
select new { Department = d, Materials = dm.Select(x => x.Material)};