1

I'm trying to verify I understand Core Data relationships and/or possibly how to handle duplicates.

In my example below, I have entity Account in a to-many relationship with entity Transaction Date. I'm thinking to-many as there will be multiple dates under the one Account.

Where I'm getting confused is that I only want to have one specific date... meaning, only one date and no duplicates. The intent is then to have entity Transaction Date to have a to-many relation with entity Event. So account XYZ will have trans date of 06/11/2012 and multiple entries for entity Event. Then account XYZ will have trans date of 06/12/2012 and multiple entries for entity Event.

Is the relationship between Account and Trans Date truly a to-many or to-one? If it is a to-many... how are duplicates handled? How do I keep only one date in entity Trans Date? If my code is adding by entries into Event and Trans Date, is some handling done there? How?

I'm guessing Account to Trans Date should be to-one... but really not sure at this point.

/-----------------------\          /----------------------\       /------------------\
| Account               |          | Transaction Date     |       |   Event          |
|-----------------------|          |----------------------|       |------------------|
| name                  |          | addDate              |       |  amount          |
| balance               |          |                      |       |                  |
|-----------------------|          |----------------------|       |------------------|
| heldByAcct            | <-\      |                      |       |                  | 
|                       |     \->> | inAcct               |       |                  |
|                       |          | heldByEvent          |<-\    |                  |
\-----------------------/          \----------------------/   \->>| inTrans          |
                                                                  \------------------/
Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
BlizzofOZ
  • 115
  • 1
  • 2
  • 13

2 Answers2

1

I'm not sure I understood what you are trying to achieve but I'll try to give you some suggestions.

First

If an Account can have only one Transaction Date, I think you should set a one-to-one relationship. In this manner you are sure that one Account has a Transaction Date and viceversa. Behind, Core Data will set up your db so that your Account table will have a field for the ID of the corresponding Transaction Date object.

Second

If you are setting up a checkout mechanism and the Account can have multiple transaction (e.g. only one per day) you need to set up a one-to-many relationship. If you need to check for a single transaction per day, you need to perform the check manually. Set a request against Transaction Date with a predicate for a specific Account and date and see if the count is greater than one. If no, add that Transaction Date.

NSInteger count = [fetchRequest countForFetchRequest:&error]; // query against `Transaction Date`
if(count >= 1) // not allowed
else // allowed

Usually when I need to check for duplicates, I use a guid as an attribute for an entity (e.g. guid of type NSString). So, in your Transaction Date you could use such a mechanism. Then you could set the fetch request with a predicate like the following:

[NSPredicate predicateWithFormat:@"guid == %@ AND inAcct == %@", @"12345", [self currentAccount]];

Each time you insert a new Transaction Date you could generate a new guid based on the date (without time) and the specific Account (use your own protocol to do this).

Thinking on it, you could also save and check the date without its time part (category-on-nsdate). I think it will work but you need to try. By means of this you could simply use a predicate without a guid. For example:

[NSPredicate predicateWithFormat:@"addDate == %@ AND inAcct == %@", [self currentDate], [self currentAccount]];

Hope it helps.

Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
  • Think of a checkbook register... Under bank xxxx (Account), on date 06/11/2012 (Trans Date), I have many entries (Event). Then account xxxx, on date 06/12/2012 I have more entries. I've tried a to-one relationship between Account & Trans Date, but when I add two or more events, I check fetchrequest count against Trans Date and it is more than one. I only want on object for date 06/11/2012. Sorry for the bad description. I just may not be totally wrapping my head around how this works. – BlizzofOZ Jun 12 '12 at 16:54
  • You need to check it manually as I suggested in the second way (I have an edit to distinguish the two different solutions). In addition, you could provide the code you use to add the events, maybe I could help you. – Lorenzo B Jun 12 '12 at 17:42
  • No, no... I just needed a verification and a push in the right direction. I really appreciate the long answer and I understand the concept you are showing. I'm a programmer in older languages and know keyed DBs, but I wasn't sure if I was mis-understanding how Core Data works. If I get stuck, I'll be back again! – BlizzofOZ Jun 12 '12 at 17:56
0

To model a transaction register, I'd suggest making addDate a property of Event and removing Transaction Date entirely.

It significantly simplifies the work you need to do to manage the object graph, and removes the need to de-duplicate the dates.

If you need to produce a list of unique dates, you can do it on the fly with distinctUnionOfSets as described in the answer to this question: CoreData get distinct values of Attribute.

Community
  • 1
  • 1
paulmelnikow
  • 16,895
  • 8
  • 63
  • 114
  • Oh nice! The reason why I made Transaction Date was to be able to put the dates in sections in a table view. Thinking I can get a object count from entity Transaction Date to set nubmerOfSectionsInTableView. That possible with distinctUnionOfSets? – BlizzofOZ Jun 13 '12 at 11:51
  • Since you need the values for the table view too, you can just invoke `count` on the result NSSet to get the count. But yes, you could separately perform a count if you need to, with `@count.addDate`. – paulmelnikow Jun 13 '12 at 14:07
  • Good point... I apologize as I'm very new to this. I'd like to, at some point, understand how my example would work, but I think moving addDate to Event makes it more simpler as you said. I originally had it this way, but again, I thought I'd have to do it this way to get a count for the header sections in table view to work. Every step is a learning experience! – BlizzofOZ Jun 13 '12 at 14:14
  • Sounds like you're picking it up. There's no need to apologize. – paulmelnikow Jun 13 '12 at 14:20
  • I've changed the model as stated... get error: "valueForUndefinedKey: the entity Account is not key value coding-compliant for the key "@distinctUnionOfSets" NSSet *uniqueName = [account valueForKeyPath:@"@distinctUnionOfSets.addDate"]; – BlizzofOZ Jun 13 '12 at 16:23
  • That makes sense, since `account` doesn't have that attribute. I think you need to invoke it on `account.transactions` or `account.events` instead. – paulmelnikow Jun 13 '12 at 16:43
  • After some trial & error, realized that I needed to setResultType to a dictionary, no errors but not working yet. Now trying to understand using NSExpression. Confused on having to use expressionForFunction... If I'm only want the unique values of addDate, why would I need to use a function like MIN, MAX, etc. How do I do without using function? Can't find any examples... – BlizzofOZ Jun 14 '12 at 16:46
  • From looking at those other answers, I don't think you need NSExpression or even NSFetchRequest. Why not post a new question? – paulmelnikow Jun 14 '12 at 16:50
  • Yeah, I see that I went off on a tangent. Agreed... I'll post question more pertintent to our discussion. Thanks! – BlizzofOZ Jun 14 '12 at 19:09