CoreData (IOS) Unique Constraint on Multiple columns? - iphone

Is it possible to, in CoreData for an iPhone app, have a Unique Constraint on Multiple columns?
For example:
have Event, EventItems, Items entities
the EventItems entity has a column ORDER
so the ORDER column for an EventItem should be unique for all it's instances relating to the same EVENT
So questions are:
How could I setup this constraint in coredata?
If it's not directly support any suggestions re how to put in place programmatically?

To do
For any core data constraint that operates on more then a single managed object at once you want to look at implementing:
- (BOOL)validateForDelete:(NSError **)error
- (BOOL)validateForInsert:(NSError **)error
- (BOOL)validateForUpdate:(NSError **)error
(I normally have core data make a .h and .m file for the entity, and then make my own category for things like this so I don't have as much work if I change the entity a little later)
If you have something that only needs to make sure values in a single managed object are correct you can use -validate<Key>:error:
To do what you are looking for I would make EventItems' validateForInsert/validateForUpdate
call a common method (maybe validateUniqueOrder). In that method I would use the relationship from EventItems to Event, and then fetch all the EventItems relating to the Event, and then check for uniqueness. I have fairly small sets of relations, so I didn't bother with anything fancy, but if you have a lot of event items associated with given events you might look into NSFetchRequests' setPropertiesToFetch method. Or maybe you can come up with a query that can directly search for duplicated values (I never could, so if you do, reply here to enlighten me).

How could I setup this constraint in coredata?
You control what goes into the data store, so you can impose any constraints you like, no matter how complex. But Core Data is not a database, and it doesn't implement the kinds of automatic constraints that you typically find in a RDBMS.
If it's not directly support any suggestions re how to put in place programmatically?
I'd do a check at the point in your code where you create or modify the affected object. In your case, you could create a custom setter for EventItem's 'order' property that compares the proposed 'order' to that of all the other EventItems related to the same event. Or, you might put the check in Event, and use an appropriate accessor to check any new EventItems as they're added.

Unique Constraints make sure that records in an Entity are unique by the given fields. But unique constraints along with To-Many relationship leads to a lot of weird issues while resolving conflicts.
e.g. “Dangling reference to an invalid object.”
This post is basically focused to a small problem that may take days to fix.
http://muhammadzahidimran.com/2016/12/08/coredata-unique-constraints-and-to-many-relationship/

Related

NSManagedObject identification number

Ok, it seems like I'm asking a noob question (maybe I am and I have just been overlooking important details), but I am looking for a "distinguishing" number/attribute about a generic NSManagedObject that I could use as an ID number (I cannot use the name b/c I want to allow the user to create entities with the same names). If this is not existent please explain how I would recreate this. I understand that I could just add an attribute for this and increment a static variable (ex: currentId) but if I do then I have to consider an entity being deleted then how do I logically place the next inserted entity at that index and then return to the last index.
Core Data does not have the notion of an auto-incremented ID field, keep in mind Core Data is an object graph, not a database. It just happens that a datastore could be backed by a database system, a perfect example is SqlLite.
NSManagedObjectId is kind of like a URL with a GUID to be unique. If you want some sort of auto-incremented id you will have to handle this on your own, there are obviously many different ways you might go about this. You could have a separate entity that stores the last id assigned and read it every time you create a new record, increment the value, use that as your new ID and increment the stored value. This would solve your delete problem if you don't want an ID to be re-used. There are obvious concurrency issues here that you may need to solve. Another approach could be to store the ID in a file on the file system, or in NSUserDefaults, just be sure to take account for concurrency and do not accidentally assign the same ID twice.
There is an objectID method for NSManagedObjects, although I do not believe that they are created in any kind of order.
Personally I would just use and ID attribute. What I don't understand is why deleting would cause any problems. The ID would just sit behind the scenes, there wouldn't be any real reason to show it to the user, right?
It seems like you could use a NSNumber identification row on your entities and then simply keep track of how many objects you have (either by keeping a var or fetching the max value from your storage).
Here I found a few examples that might help you achieve your goal.
link

I don't need/want a key!

I have some views that I want to use EF 4.1 to query. These are specific optimized views that will not have keys to speak of; there will be no deletions, updates, just good ol'e select.
But EF wants a key set on the model. Is there a way to tell EF to move on, there's nothing to worry about?
More Details
The main purpose of this is to query against a set of views that have been optimized by size, query parameters and joins. The underlying tables have their PKs, FKs and so on. It's indexed, statiscized (that a word?) and optimized.
I'd like to have a class like (this is a much smaller and simpler version of what I have...):
public MyObject //this is a view
{
Name{get;set}
Age{get;set;}
TotalPimples{get;set;}
}
and a repository, built off of EF 4.1 CF where I can just
public List<MyObject> GetPimply(int numberOfPimples)
{
return db.MyObjects.Where(d=> d.TotalPimples > numberOfPimples).ToList();
}
I could expose a key, but whats the real purpose of dislaying a 2 or 3 column natural key? That will never be used?
Current Solution
Seeming as their will be no EF CF solution, I have added a complex key to the model and I am exposing it in the model. While this goes "with the grain" on what one expects a "well designed" db model to look like, in this case, IMHO, it added nothing but more logic to the model builder, more bytes over the wire, and extra properties on a class. These will never be used.
There is no way. EF demands unique identification of the record - entity key. That doesn't mean that you must expose any additional column. You can mark all your current properties (or any subset) as a key - that is exactly how EDMX does it when you add database view to the model - it goes through columns and marks all non-nullable and non-computed columns as primary key.
You must be aware of one problem - EF internally uses identity map and entity key is unique identification in this map (each entity key can be associated only with single entity instance). It means that if you are not able to choose unique identification of the record and you load multiple records with the same identification (your defined key) they will all be represented by a single entity instance. Not sure if this can cause you any issues if you don't plan to modify these records.
EF is looking for a unique way to identify records. I am not sure if you can force it to go counter to its nature of desiring something unique about objects.
But, this is an answer to the "show me how to solve my problem the way I want to solve it" question and not actually tackling your core business requirement.
If this is a "I don't want to show the user the key", then don't bind it when you bind the data to your form (web or windows). If this is a "I need to share these items, but don't want to give them the keys" issue, then map or surrogate the objects into an external domain model. Adds a bit of weight to the solution, but allows you to still do the heavy lifting with a drag and drop surface (EF).
The question is what is the business requirement that is pushing you to create a bunch of objects without a unique identifier (key).
One way to do this would be not to use views at all.
Just add the tables to your EF model and let EF create the SQL that you are currently writing by hand.

Callbacks on entity on created/updated

I would like to know when entities in a certain database table are either created or updated. The application is essentially a CMS, and I need to know when changes are made to the content so that I can reindex them for searches.
I know that the autogenerated LINQ to EF class has overridable methods for when certain fields change, but I need to know when the whole object is created/updated, not just a single field. I tried putting it in OnCreated, only to find that meant OnObjectInitialized and not OnObjectInsertedIntoDBTable xD
I did some searching and came across this link. The "Entity State" section looks like its what I want, but I'm not sure how to use this information. Where do I override those methods?
Or perhaps there is a another/better way?
(I also need to know this for another part of the system, which will send notifications when certain content is changed. I would prefer this code to execute automatically when the insert/update occurs instead of placing it in a controller and hoping hoping I always call that method.)
You need to get ObjectStateEntry(s) from the ObjectStateManager property of the ObjectContect.
var objectStateEntries = this.ObjectStateManager.GetObjectStateEntries();
This entries contain every object state you've pulled down per context and what kind of actions where performed on them.
If you are using EF4 you can override the SaveChanges method to include this functionality. I've used this technique to audit every change that occurs in the database instead of triggers.

Create a Core Date Entity Instance But not want it to be stored(non-persistent)

Sometimes I need instantiate CoreDateEntity to store some infomations for temporarily using.
But I needn't it be stored into DB.
currently I created a similar class which have same structures as the CoreDateEntity does.
It works well but I have to do many datas transfer between Two models.
Is there any better way to handle this?
Thanks for all the replies. but you guys just give me half answer of this. consider about this, I need place some entity without MOC into current database pool, how could I do this? I already checked the documents of CoreData, seems I didn't find API to transfer one entity from MOC to another MOC(manage object context).
According to Apple docs you can initialize a managed object without context if you specify nil as context.
- (id)initWithEntity:(NSEntityDescription *)entity insertIntoManagedObjectContext:(NSManagedObjectContext *)context
You can assign entities to different stores when you set up the data model. Have one store be the persistent store and the other an in-memory store. You can't form relationships across stores but it sounds like you don't need that.
To assign a configuration, hit the configuration tab (the one with the wrench icon) in the entity detail (where you give it its name, class and parent). When you create the persistent store, add the configuration name to the options dictionary.
Update:
I think you maybe overcomplicating things. It sounds like you have some managed objects that will be temporary and some that will persisted but sometimes you may want to save the temporary objects. I don't think you should bother trying to separate out the "temporary" objects. Doing so just adds complexity without any performance benefit. Instead, just use ordinary persisted objects and then delete the ones you don't want.
Always try the simplest solution first.
Use two different managed object context's and only save the objects from one context. Be careful not to set relationships between objects of two different context's - this doesn't work.

iphone SDK: Arbitrary tableview row reordering with core data

What is the best way to implement arbitrary row reordering in a tableview that uses core data? The approach that seems obvious to me is to add a rowOrder attribute of type Int16 to the entity that is being reordered in the tableview and manually iterate through the entity updating the rowOrder attributes of all the rows whenever the user finishes reordering.
That is an incredibly inelegant solution though. I'm hoping there is a better approach that doesn't require possibly hundreds of updates whenever the user reorders things.
If the ordering is something that the data model should modal and store, then the ordering should be part of the entity graph anyway.
A good, lightweight solution is to create an Order entity that has a one-to-one relationship to the actual entity being ordered. To make updating easy, create a linked-list like structure of the objects. Something like this:
Order{
order:int;
orderedObject<--(required,nullify)-->OrderObject.order
previous<--(optional,nullify)-->Order.next;
next<--(optional,nullify)-->Order.previous;
}
If you create a custom subclass, you can provide an insert method that inserts a new object in the chain and then sends a message down the next relationships and tells each object to increment its order by one then the message to its next. A delete method does the opposite. That makes the ordering integral to the model and nicely encapsulated. It's easy to make a base class for this so you can reuse it as needed.
The big advantage is that it only requires the small Order objects to be in alive in memory.
Edit:
Of course, you can extend this with another linked object to provide section information. Just relate that entity to the Order entity then provide the order number as the one in the section.
There is no better way and that is the accepted solution. Core Data does not have row ordering internally so you need to do it yourself. However it is really not a lot of code.