Using Core Data, I have two entities that have many-to-many relationships. So:
Class A <<---->> Class B
Both relationships are set up as 'ordered' so I can track they're order in a UITableView. That works fine, no problem.
I am about to try and implement iCloud with this Core Data model, and find out that iCloud doesn't support ordered relationships, so I need to reimplement the ordering somehow.
I've done this with another entity that has a one-to-many relationship with no problem, I add an 'order' attribute to the entity and store it's order information there. But with a many-to-many relationship I need an unknown number of order attributes.
I can think of two solutions, neither of which seem ideal to me so maybe I'm missing something;
Option 1. I add an intermediary entity. This entity has a one-to-many relationship with both entities like so:
Class A <<--> Class C <-->> Class B
That means I can have the single order attribute in this helper entity.
Option 2. Instead of an order attribute that stores a single order number, I store a dictionary that I can store as many order numbers as I need, probably with the corresponding object (ID?) as the key and the order number as the value.
I'm not necessarily looking for any code so any thoughts or suggestions would be appreciated.
I think your option 1, employing a "join table" with an order attribute is the most feasible solution for this problem. Indeed, this has been done many times in the past. This is exactly the case for which you would use a join table in Core Data although the framework already gives you many-to-many relationships: if you want to store information about the relationship itself, which is precisely your case. Often these are timestamps, in your case it is a sequence number.
You state: "...solutions, neither of which seem ideal to me". To me, the above seems indeed "ideal". I have used this scheme repeatedly with great performance and maintainability.
The only problem (though it is the same as with a to-one relationship) is that when inserting an item out of sequence you have to update many entities to get the order right. That seems cumbersome and could potentially harm performance. In practice, however, it is quite manageable and performs rather well.
NB: As for arrays or dictionaries to be stored with the entity to keep track of ordering information: this is possible via so-called "transformable" attributes, but the overhead is daunting. These attributes have to be serialized and deserialized, and in order to retrieve one sequence number you have to get all of them. Hardly an attractive design choice.
Before we had ordered relationships for more than 10 years, everyone used a "helper" entity. So that is the thing that you should do.
Additional note 1: This is no "helper" entity. It is a entity that models a fact in your model. In my books I always had the same example:
You have a group entity with members. Every member can belong to many groups. The "helper" entity is nothing else than membership.
Additional note 2: It is hard to synchronize such an ordered relationship. This is why it is not done automatically. However, you have to do it. Since CD and synchronizing is no fun, CD and synchronizing a model with ordered relationship is less than no fun.
Related
Need help with a orm request.
There are 2 tables. Author and Book (names for example, so you don't need to look at the logic), linked through FK.
class Book(models.Models):
title = models.Charfield(...)
class Author(models.Model):
book = models.ForeignKey(Book)
Need to group the authors by the book and go through them in a loop. The question is how to select only the last 50 authors of each book.
I can write this:
for book in Book.all()
for author in book.author_set.all()[:50]:
....
But this is not an optimal solution.
Bad answer, I didn't realize that slicing implies a new query. My bad, don't look further down.
To optimize your query, you need to use the prefetch_related() method:
prefetch_related()
Returns a QuerySet
that will automatically retrieve, in a single batch, related objects
for each of the specified lookups.
This has a similar purpose to select_related, in that both are
designed to stop the deluge of database queries that is caused by
accessing related objects, but the strategy is quite different.
select_related works by creating an SQL join and including the fields
of the related object in the SELECT statement. For this reason,
select_related gets the related objects in the same database query.
However, to avoid the much larger result set that would result from
joining across a ‘many’ relationship, select_related is limited to
single-valued relationships - foreign key and one-to-one.
prefetch_related, on the other hand, does a separate lookup for each
relationship, and does the ‘joining’ in Python. This allows it to
prefetch many-to-many and many-to-one objects, which cannot be done
using select_related, in addition to the foreign key and one-to-one
relationships that are supported by select_related.
for book in Book.all().prefetch_related()
for author in book.author_set.all()[:50]
You also need to order your book.author_set queryset to make sure you get the latest entries.
This is more or less a general question and not about any specific ORM or language in particular: this question comes up regardless of your ORM preference.
When mapping a many-to-many relationship it is possible to obscure the intermediary table or to make the intermediary table a part of your model. In the case that the intermediary table has valuable data beyond the relationship, how do you handle the mapping?
Consider the following tables:
CaseWorker (id, first_name, last_name)
CaseWorkerCases (case_worker_id, case_id, date_opened, date_closed)
Case (id, client_id, field_a, field_b)
As a programmer I would really rather be able to do:
CaseWorker.Cases
than
CaseWorker.CaseWorkerCases.Cases
On the one hand, the table CaseWorkerCases contains useful data and hiding the intermediary table makes accessing that data less than convenient. On the other, having to navigate through the intermediary table makes the common task of accessing Cases seem awkward.
I supose one solution could be to expose the intermediate table in the model and then give the CaseWork object a wrapper property could work. Something like:
public IEnumerable<Case> Cases
{
get{return (from caseWorkerCase in this.CaseWorkerCases
select caseWorkerCase.Case);}
}
But that also seems wrong.
I regard many-to-many mappings as just a notational abbreviation for two one-to-many mappings with the intermediate table, as you call it, enabling simplification of the relationships. It only works where the relationships do not have attributes of their own. However, as understanding of the particular domain improves, I usually find that many-to-many mappings usually need to be broken down to allow attributes to be attached. So my usual approach these days is to always simply use one-to-many mappings to start with.
I don't think your workaround is wrong. The complexities of these models have to be coded somewhere.
I have a blog post about this exact topic: Many-to-many relationships with properties
I'm currently writing my first project using core data, and am having trouble working out how to query the relationship between some of my data.
In sql language, i have a Country table, which joins to a CountryLink M-M table containing the following fields:
countryId1
countryId2
bearing
What would be the correct way to model this in Core Data?
So far i have set up a single Country entity and a CountryLink entity (containing only a bearing field) and have added two 1-to-Many relationships from Country to CountryLink ('CountryLink1' and 'CountryLink2').
I've run the project and looked at the Sqlite db structure produced by Core Data (found here, using this sqlite gui), and the M-M join table seems correct (it contains the bearing, CountryLink1 and CountryLink2 fields), but i'm not sure how i would go about carrying out a fetch request for a single Country NSManagedObject to return an array of related Countries and their bearings?
Any help or related links would be much appreciated.
Thanks, Ted
First a word of warning:
Core Data is not SQL. Entities are not tables. Objects are not rows. Columns are not attributes. Core Data is an object graph management system that may or may not persist the object graph and may or may not use SQL far behind the scenes to do so. Trying to think of Core Data in SQL terms will cause you to completely misunderstand Core Data and result in much grief and wasted time.
See the Tequilla advice
Now, forgetting SQL and thinking in object graphs, your entities would look something like this:
Country{
someAttribute:string // or whatever
countryLinks<-->>CountryLink.country
}
CountryLink{
countryID1:string // or whatever
countryID2:string // or whatever
country<<-->Country.countryLinks
}
As you add Country and CountryLink objects you add them to the relationships as needed. Then to find CountryLink objects related to a specific Country object, you would perform a fetch on the Country entity for Country objects matching some criteria. Once you have that object, you simply ask it for the CountryLink objects in its countryLinks relationship. And your done.
The important thing to remember here is that entities in combination with managedObjects are intended to model real-world objects, conditions or events and the relationship between the same. e.g. a person and his cars. SQL doesn't really model or simulate, it just stores.
My application is CoreData based but they may be a common theory for all relational databases:
I have a Output-Input to-many relationship in my model. There are potentially an unlimited number of links under this relationship for each entity. What is the best way to identify a specific input or output?
The only way I have achieved this so far is to place an intermediate entity in the relationship that can hold an output and input name. Then an entity can cycle through its inputs/outputs to find the right relationship when required. Is there a better way?
Effectively I am trying to provide a generic entity that can have any number of relationships with other generic entity.
Apologies if my description isn't the clearest.
Edit in response to the answer below:
Firstly thank you for your response. I certainly have a two-way too-many relationship in mind. But if a widget has 2 other widgets linked to its Inputs relationship what is the best way of determining which input is supplying, say, 'Age' or 'Years Service' when both may have this property but I'm only interested in a specific value from each?
I'm as confused as Joshua - which tells me that it may be that you haven't got a clear picture of what you're trying to achieve or that it is somewhat complex (both?).
My best guess is that you have something like:
Entity Widget
Attributes:
identifier
Relationships
outputWidgets <<->> Widget
inputWidgets <<->> Widget
(where as per standard a ->> is a to-many relationship and <<->> is a to-many relationship with a to-many reverse relationship).
So each widget will be storing the set of widgets that it has as outputs and the set of widgets it has as inputs.
Thus a specific widget maintains a set of inputWidgets and outputWidgets. Each of these relationships is also reversed so you can - for any of the widgets in the input or output - see that your widget is in their list of inputs or outputs.
This is bloody ugly though.
I think your question is how to achieve the above while labelling a relationship. You mention you want to have a string identifier (unique?) for each relationship.
You could do this via:
Where you create a new widgetNamedRelationship for each double sided relationship. Note that I'm assuming that every relationship is double sided.
Then for each widget you have a set of named inputs and named outputs. This also allows for widgets to be attached to themselves but only of there are separate input and output busses.
So then for your example "age" in your implementation class for Widget instance called aWidget you'd have something like:
NSPredicate *agePredicate = [NSPredicate predicateWithFormat:#"name='age'"];
NSSet *ageInputs = [aWidget.inputs filteredSetUsingPredicate:agePredicate];
Have I understood the question?
There really is no better way if you want to be able to take full advantage of the conveniences of fast and efficient in-store querying. It's unclear what you're asking in your additional comments, which I suppose is why you haven't gotten any answers yet.
Keep in mind Core Data supports many-to-many relationships without a "join table."
If Widget has many Inputs or Outputs (which I suspect could be the same entity), then a many-to-many, two-way relationship (a relationship with an inverse, in Core Data parlance) between Widget and Input is all you need. Then all you need to do is see if your Input instance is in the Widget instance's -inputs or if a Widget instance is in the Input instance's -widgets.
Is that what you were looking for? If not, please try to clarify your question (by editing it, not by appending comments :-)).
I have to add functionality to an existing application and I've run into a data situation that I'm not sure how to model. I am being restricted to the creation of new tables and code. If I need to alter the existing structure I think my client may reject the proposal.. although if its the only way to get it right this is what I will have to do.
I have an Item table that can me link to any number of tables, and these tables may increase over time. The Item can only me linked to one other table, but the record in the other table may have many items linked to it.
Examples of the tables/entities being linked to are Person, Vehicle, Building, Office. These are all separate tables.
Example of Items are Pen, Stapler, Cushion, Tyre, A4 Paper, Plastic Bag, Poster, Decoration"
For instance a Poster may be allocated to a Person or Office or Building. In the future if they add a Conference Room table it may also be added to that.
My intital thoughts are:
Item
{
ID,
Name
}
LinkedItem
{
ItemID,
LinkedToTableName,
LinkedToID
}
The LinkedToTableName field will then allow me to identify the correct table to link to in my code.
I'm not overly happy with this solution, but I can't quite think of anything else. Please help! :)
Thanks!
It is not a good practice to store table names as column values. This is a bad hack.
There are two standard ways of doing what you are trying to do. The first is called single-table inheritance. This is easily understood by ORM tools but trades off some normalization. The idea is, that all of these entities - Person, Vehicle, whatever - are stored in the same table, often with several unused columns per entry, along with a discriminator field that identifies what type the entity is.
The discriminator field is usually an integer type, that is mapped to some enumeration in your code. It may also be a foreign key to some lookup table in your database, identifying which numbers correspond to which types (not table names, just descriptions).
The other way to do this is multiple-table inheritance, which is better for your database but not as easy to map in code. You do this by having a base table which defines some common properties of all the objects - perhaps just an ID and a name - and all of your "specific" tables (Person etc.) use the base ID as a unique foreign key (usually also the primary key).
In the first case, the exclusivity is implicit, since all entities are in one table. In the second case, the relationship is between the Item and the base entity ID, which also guarantees uniqueness.
Note that with multiple-table inheritance, you have a different problem - you can't guarantee that a base ID is used by exactly one inheritance table. It could be used by several, or not used at all. That is why multiple-table inheritance schemes usually also have a discriminator column, to identify which table is "expected." Again, this discriminator doesn't hold a table name, it holds a lookup value which the consumer may (or may not) use to determine which other table to join to.
Multiple-table inheritance is a closer match to your current schema, so I would recommend going with that unless you need to use this with Linq to SQL or a similar ORM.
See here for a good detailed tutorial: Implementing Table Inheritance in SQL Server.
Find something common to Person, Vehicle, Building, Office. For the lack of a better term I have used Entity. Then implement super-type/sub-type relationship between the Entity and its sub-types. Note that the EntityID is a PK and a FK in all sub-type tables. Now, you can link the Item table to the Entity (owner).
In this model, one item can belong to only one Entity; one Entity can have (own) many items.
your link table is ok.
the trouble you will have is that you will need to generate dynamic sql at runtime. parameterized sql does not typically allow the objects inthe FROM list to be parameters.
i fyou want to avoid this, you may be able to denormalize a little - say by creating a table to hold the id (assuming the ids are unique across the other tables) and the type_id representing which table is the source, and a generated description - e.g. the name value from the inital record.
you would trigger the creation of this denormalized list when the base info is modified, and you could use that for generalized queries - and then resort to your dynamic queries when needed at runtime.