I have a question about the Core Data Model and the Cascade Delete Rule.
My Core Data Model is this one:
As you can see the User Entity has a "To Many" Relationship with the Orders Entity.
Also the Orders Entity has a parent entity called Cuisines, as each Order needs to be from a list of available Cuisines.
The User To Orders Relationship delete Rule is Cascade (the inverse is nullify) as I want all orders to be deleted if the user object is deleted.
My question is what happens with the Cuisines Entity if I delete the User?
The Cuisines should be available for all orders placed for other Users as well, so it must persist. Will it be also deleted?
If yes, how should I create my model and set the delete rules to avoid this?
Specifying Cuisines as the parent entity for Orders means that each Orders object is a Cuisine - albeit a specific "type" of Cuisine. Each Order has three attributes: numOfOrders, rating and name. When you delete an Order (albeit through a cascade rule), you are deleting one object with all three attributes - there isn't a separate Cuisines object to be deleted.
But you want each order to be from a list of available cuisines. So replace the parent/subentity link between Orders and Cuisines with a relationship. Each Cuisine can be related to several different Orders, so the relationship would be to-many. Conversely, each Order relates to only one Cuisine, so the inverse relationship will be to-one. When you delete an Order, you want the related Cuisines to remain (for use in other Orders) so the delete rule would be "nullify".
Related
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).
I have two subgrids
Parent
Children
Now I will be adding entries to it from the contact entity
What I want to achieve is, I want to create parent-child relationship among the data that are there in these two subgrids so that I can use it for querying in future
Usage scenario:
I have a entity form for a entity called as MedicalCase
MedicalCase form will have two subgrids for "Children" and "Parent"
Now I will be able to add children and parent records to subgrid from the Contact entity
For these records in the parent and children subgrid, I want to specify, which parent is the father/mother of which child
I don't have the luxury of editing the Contact records, is there any other means that you can think of?
Someway in which I can record the relationship between child and parent in the subgrids
Hope I am clear enough, feel free to ask me if you need any clarifications
I'm having a hard time understanding the situation exactly, but after several re-reads it sounds like you need a custom many-to-many relationship entity. Create an entity called ChildParentRelationship (CPR) which should have a lookup to Child and a lookup to Parent. Your Medical Case form should have a sub-grid for CPR entity. When a user creates a new CPR record, they will specify the Child and Parent. Does that get you what you need?
Lots of examples like order and order lines makes sense, like:
Order is an AR that contains OrderLines
Customer is an AR that contains Orders.
Question is, what is the AR that contains Customer?
I guess it can be something like "shop".
So, shop.AddCustomer(customer)...
but, how to get shop?
If it's an AR (entity) it has an id, so shop.GetById(shopId). If I only have one shop, how does this work with persistence?
Should I have a table (shops) with one line?
Shop is an in-memory object with a collection of Customers?
You got that wrong there. Aggregates do not contain other aggregates! They can only reference them by ID.
An aggregate is a group of entities and value objects that are closely related. The aggregate forms a consistency boundary around them. The Aggregate Root is the root entity in that aggregate that is globally addressable. So in your example with Order and OrderLines, Order could indeed be the AR.
Customer on the other hand, would only reference Orders by ID if it is a separate aggregate.
To retrieve an aggregate, you typically use a Repository. You load an aggregate through the repository by specifying the ID of the aggregate, or some other suitable search parameter.
I have a domain model
Customer - Aggregate root - because an order can't exist without a customer
Order - entity
OrderStatus - value object
In my form I need a list of all OrderStatuses.
Should I fetch an empty customer entity(AR) from repository with an empty order entity which is containing a list of all OrderStatuses? This is awkward.
Well, it always depends on your problem domain, but lacking further info, I would say you probably need to break your modeling a little bit.
Even though an Order can't exist without a Customer, it will not be a child entity under the Customer AR. You need to introduce the notion of Bounded Contexts.
Customer would be the AR of one BC, while Order would be the AR of its own BC.
In that case, you would reference Customer from Order with a CustomerId property (not with an object reference) because they belong to different contexts, and as such they could even live in separate microservices, in separate databases.
You see where I'm going: it makes no sense to fetch an empty Customer, with an empty Order (or list of Orders) just to reach a list of Order Statuses.
Even if Order and Customer did belong to the same BC, OrderStatus is Reference Data, and would be better represented by an enum type (or better, with the Enumeration Pattern).
Have a look at this additional info:
Reference data as code
Entities, Value Objects, Aggregates and Roots
Can someone check my class diagram because I am not too good at drawing this type of uml diagram
A User can be a PersonalUser or a BusinessUser
An Administrator is a special type of PersonalUser
A PersonalUser or BusinessUser can create many Auction
But an Auction can be created by only one PersonalUser or only one BusinessUser
There an Auction cannot exist without an PersonalUser or a BusinessUser
An Auction can contain only one Item
An Item can be in only one Auction
An Item cannot exist without an Auction
An Auction cannot exist without an Item
An Item has one Category
Category can has many item
An Item cannot exist without a category
A Category can has a Parent Category but this is not mandatory
A Category can has many Attributes
But an Attribute is for only one Category
An Attribute cannot exist a Category
An Attribute can has many AttributeOption
But an AttributeOption is linked to only one Attribute
An AttributeOption cannot exist without an Attribute
An Auction can has many bids
A bid is only for one auction
A Bid cannot exist without an Auction and a Personal User or a BusinessUser
An Item can has many picture
A picture is only for once item and a picture cannot exist without an Item
A User can create many ForumTopics but a ForumTopic can be created only by one User
A ForumTopics can contain one or more ForumMessage
A ForumTopic cannot exist without a User and a ForumMessage cannot exist without a ForumTopic
A BusinessUser can has many BusinessContactNumber but a BusinessContactNumber is only for one BusinessUser
A BusinessContactNumber cannot exist without a Business
At first glance, you used a lot of aggregations. This is quite uncommon. I have never seen a good example of when an aggregation is justified. It's usually either a plain association (no whole-part relationship) or a composition (the part is deleted when the whole is deleted).
Cannot exists without does not imply aggregation. A proper multiplicity is sufficient. Can create does not imply aggregation. Creation is usually modeled with an appropriately stereotyped use-relation (i.e. dashed arrow), unless an association between the creator and the creation exists (in which case creation need not be mentioned explicitly).
4 But an Auction can be created by only one PersonalUser or only one BusinessUser.
Then the multiplicity of the Auction-PersonalUser association cannot be 1 at the PersonalUser end (because the Auction might have been created by a BusinessUser) and the multiplicity of the Auction-BusinessUser association cannot be 1 at the BusinessUser end (for much the same reason). Use 0..1 as multiplicity, but beware of what I will write about 3.
3 A PersonalUser or BusinessUser can create many Auction
This is equivalent to a User can create many Auction.
6 An Auction can contain only one Item
7 An Item can be in only one Auction
8 An Item cannot exist without an Auction
9 An Auction cannot exist without an Item
Then there is a single association between Item and Auction with multiplicity of 1 at both ends. Don't make aggregations out of it and don't use two associations for it.
13 A Category can has a Parent Category but this is not mandatory
That would be made clear if you label the association ends.
25 A User can create many ForumTopics but a ForumTopic can be created only by one User
This is only vaguely related to Auctions and might as well exists independent of them. Put the Forum stuff into a separate package. Then maybe the auction stuff and the user stuff also deserve a separate packages.
BTW: You did not mention the Bidding Service. It seems solely to model the concept of theses objects do not exist in thin air, they are actually used by some software. In that case, leave it out.
I largely agree with previous respondent, so I will present only differences and additional opinions.
To be a bit more precise, "Can create..." should be depicted using dependency relationship (not uses).
It is not entirely equivalent if some distinction should exist. You might use User class with an enumeration or UserType class if you want to avoid enumerations for some reason.
6.-9. So no Auction or Item object can exist. Either loosen the relationship in one way and use composition or merge those two to one class or create an association class.
Maybe one category can contain many subcategories? If true, edit the corresponding multiplicity.
Same as 4., view the other answer.
Also rethink the amount of classes in your design. Classes are not just data holders, they should have behaviour. What will be the behaviour of AttributeOption or Attribute or BusinessContact etc? Getters and setters do not count for a behaviour... I guess you planned to have all of this behaviour in BidingService, so I advise you to remove it and split those methods according to what class of objects should be responsible for behaviour achieved through the respective method.