Say I have a client dataset CDSPerson that acts as a wrapper around a Persons database table. Say I have another table, PersonBenefits, that joins 1:1 back to the Persons table.
Say I wrap a Delphi class around CDSPerson, PersonClass, and another class around CDSPersonBenefits, PersonBenefitsClass, to read and write records. PersonBenefitsClass inherits from PersonClass so it can provide data from both tables. I'd like to be able to write data back to either table through PersonBenefitsClass.
Has anyone developed a clean way to handle the SQL query, provider flags and commit logic in the inherited class so that (a) fields stay aligned with the parent class and (b) both database tables can be updated?
Is there a reference for this that I can't find? Is this just a bad idea? I'm using Delphi 2007.
If you're going to develop a business-object-to-database mapping framework, (commonly known as ORM, Object-Relational Mapper,) you're going to need to put in a bit of architecture to make relationships like this work properly. Here's one way to do it:
PersonClass and BenefitsClass both inherit from BusinessObjectClass. BusinessObjectClass is a base class that contains the general logic to interact with the dataset. It has a list object of some sort that contains a list of relation objects.
Each relation object is a special object that contains either one or a list of BusinessObjectClass descendants, plus extra data describing the foreign-key relationship between the two tables. When BusinessObjectClass does its queries and its updates, it needs to iterate through all its relation objects and have them do their own queries and updates as appropriate.
In your composite object, (PersonWithBenefitsClass,) in the constructor, call inherited and then set up a relation object that describes the related BenefitsClass. Make sure that any inserts of new objects are done in the right order to preserve referential integrity.
That's the basic idea. (One basic idea. There are probably plenty of other ways to do it.) I'll leave the details of exactly how you implement it up to you.
Related
I just started reading this guide: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/KeyConcepts.html#//apple_ref/doc/uid/TP40001075-CH30-SW1
And it basically has (in my opinion) two big contradictions:
I get them both, but basically, if I follow the first "implement a custom class to the entity from which classes representing subentities also inherit"-statement, then ALL my entities will be put in the same table. Which could cause performance issues, according to the NOTE.
How big of a performance hit would I run into of it create a "custom super entity"?
You can use the inheritance mechanism to get a default database structure. From your link:
If you have a number of entities that are similar, you can factor the common properties into a superentity, also known as a parent entity.
There is no contradiction. The documentation is just telling you what the database structure is going to be when you use a certain facility. (And it is the standard database table idiom for inheritance.) Using the entity inheritance mechanism automatically declares and implements default parent-child class inheritance functionality along with a parent table. Otherwise you do any parent-child class inheritance declaration and implementation by hand. Each comes with certain performance and other characteristics.
Design involves tradeoffs between costs and benefits over multiple dimensions. "Performance" itself involves multiple dimensions, and has no meaning outside of given application usage patterns. Other dimensions relevant here include complexity of both construction and maintenance.
If you query about entities as parents sufficiently frequently then it can be better to have all parent data in its own table. But if you sufficiently rarely ask for the parent data while querying about a given child type or if you sufficiently frequently need both child and parent data then it can be better to only have parent data in the child tables or table. But notice that each design performs worse at the other kind of query.
The first is talking about sub-entities. The second is talking about subclasses. These are 2 different hierarchies.
One use for sub-entities is if you have a table where you want to show cells displaying different entities. By making them sub-entities, you can fetch the parent entity and all sub-entities will be returned. This is actually how the Notes app shows the "All Notes" cell above folders, that is actually displaying the Account entity, and both Account and Folder are sub-entities of NoteContainer which is what is fetched. This does mean all of the rows are in the same table, but personally I have not experienced any performance problems but it is something to keep in mind when modifying the entities in other ways like indexes, relations or constraints for example.
I'm not familiar with this quirk of SQLite, but modeling base class/subclass relationships are usually done with different tables. There is one table that represents the base class which contains attributes common to all derivative classes (Vehiclea) and a different table for each subclass which contain attributes unique to that subclass (Cars, Trains, Airplanes).
Performance is no better or worse than any entity normalized across different tables.
In Simperiums iOS/OSX tutorial you say, each modeled object should inherit from SPManagedObject.
I didn't try it yet, but doesn't that lead to one big table in the SQLite database that contains a union of all fields of all modeled managed objects?
Yes, under the hood Core Data will tend to create a bigger table. Generally performance will suffer more from relations though, not inheritance:
Using Parent Entity in CoreData Models
We've done integrations with fairly complex inheritance hierarchies and didn't see any immediate issues with a fair amount of data.
Having said that, should you need more control over your table structure, you can avoid having a single parent for all your objects and instead either:
Manually add the ghostData and simperiumKey attributes to the objects you want to sync, and ensure their class is SPManagedObject (or ensure their custom class inherits from SPManagedObject), or
Create more than one parent entity with ghostData and simperiumKey attributes, and inherit from those for the parts of your model where it makes sense, depending on how you'd like the underlying tables to be structured.
Im about to add the persistence layer to my application, and i decided to give core data a go. Currently i map all my models to entities, which seems to work quite well. But in my current implementation i use something i call "collections" (of models) for example i have a collection of tile slots in a game.
this SlotsCollection class has methods like findNextInSameRow() findAvailableSlot() etc. What ive done with core data is i have created a Game entity and added a to many relationship to the Slot entity, Is there a way to define a class which the collection of slots should be instantiated with so i can put my logic inside that? Or is there a better way for me to structure things. I guess i could create "managers" inside my Game entity and hand in the slots when initialized
SlotManager* manager = [SlotManager alloc] initWithSlots:self.slots];
Slot* slot = [manager findAvailableSlot];
Also after i "migrated" all my models to entities, i have alot of entities that do not have any attributes but only hold references to other entities. Im abit afraid im using a wrong mindset when structuring the core data.
The class that has the collection should have the logic for that collection.
If you have a 1-to-many relationship from A to B, then you'd put the logic about this relationship into class A — and possibly some of it inside class B (depending on your needs).
Note: If you're iterating through relationships, you need to be aware of faulting behavior etc. Whenever Core Data has to do actual database work, you incur a performance hit. That's no different that plain old SQL. If you don't have to "go to disk" things are very fast. If you're using fetch request you will always do database work, and things will always be (relatively) expensive.
I've read the manual and saw some tutorial, but still, I do not understand this point.
If I use Core Data in my app, lets say I have an object that one of its properties (column in DB) is a type field. In SQL i would do another table with types and do a many-to-one connection between them.
Now, In the tutorials they say that core data is not SQLite and i should regard it as a representation of an OOP objects.
So, should I do it the same why I would in SQL? types table and a field in the object table that is a foreign key for the types table or should I create a parent entity and inherit from it, creating a new entity (class) for each of the types I need?
SQL DB, as we all know, is a representation of a OOP schema, so I don't understand the benefit of doing it the hard way with inheritance. It is much nicer in my eyes to do it with a types entity, if possible...
Am i wrong about this?
Thank you,
Erez
In my opinion, these are the hard things. You'll always want to return to database designing. It can be better to use a separate 'table', but you can also use subclasses. Maybe you have an Item class, that can have different types. Then you can maybe create the subclasses CarItem, HouseItem... Each representing a certain type of the Item class.
I have a MySQL database and would like to have a similar structure in Core Data. I am very new with using Core Data with Xcode. I have a few fundamental questions if I am doing the right thing.
My Mysql DB looks similar to this:
table.caveconditions
visibilityID
percolationID
xxxx
table.visibility
visibilityID
visibilityValue
...and so on. I would then connect the tables using JOINS
Now, I have done the Core Data modeling like this but I am not quite sure if this is the right approach.
Would be great if someone of you could tell me if this is the right way to do it. In the end I would like to use JSON strings to dump the mysql table into core data.
Thanks a lot
Chris
I have created the new schema. Is this right?
It looks good except for all the "xxxID" attributes e.g. caveID. You also need to follow the naming conventions.
You have the same attribute names with (presumably) the same values in two or more entities. This is necessary in SQL for joins but in Core Data, this is handled by objects and relationships.
Each object in Core Data is automatically universally unique. This means when you create a relationship from one object to another, that relationship concrete identifies on specific unique object.
This means you only need an attribute like caveID in the actual entity that caveID designates which in this case is (presumably) the Caves entity. You don't need the attribute in the CavesConditions entity or any other entity that has a relationship to the "Caves" entity.
(If the xxxID were just artifacts of SQL, you don't actually need them at in Core Data unless some external database your app interacts with requires them.)
A good rule of thumb to use is that any particular value should show up on only one side of a relationship and, ideally, only once in the entire data model.
Naming conventions are a little different than SQL. A Core Data entity isn't a table. An entity is more akin to a class. Each entity is supposed to describe a single instance of a managed object. How many of those instances end up in the object graph is irrelevant. Therefore, entity names are singular.
In this case, Caves should be Cave, Countries should be Country and so on.
Relationships are named after the entity they target. It is not immediate obvious but each reciprocal relationship (the default) on the visual data model editor is actually two relationships because there is one relationship description for each side. Each side has the name of the entity targeted. By convention to-one relationships have a singular name and a to-many relationship has a plural name.
So:
Caves.relConditions<-->>CaveConditons.getCave
...would become
Cave.conditons<-->>CaveConditon.cave
The naming conventions are important because Objective-C uses conventions names to generate and search for accessor methods.
CoreData is NOT a database. Remodel your data as simply as you can and in a way that suits how it will be used in your application and do not think about joins or structure based optimization. You do not have control over the backing schema of a CoreData object model. This is the hardest concept you must get over when starting to use CoreData, but once you do, you will be better off.