mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-11 20:00:30 +01:00
Objects relations won't update with fetchExisting(object) #31
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Jeehut on GitHub (Jan 22, 2016).
Hi, I'm currently writing an app where I try to partition all of its different parts into modules which I can test much easier. One module is responsible for storing the data so I wrote a framework that does exactly that using CoreStore. In my tests everything seemed to work except for refetching the related set of objects of a
NSManagedObjectsubclass.To be more specific, here's the test that fails (I'm using Quick and Nimble for testing):
Now my question is basically why the
itemsproperty of theWordPoolsubclass ofNSManagedObjectstill contains one object after deleting the only item existing (and even checking it is deleted successfully two lines right before the failing line) when it should be empty. Am I missing something here? Did I even use CoreStore the way you intended it to? I like to have methods as simple asall(),create(..),update(...)anddestroy()in usage so things are kept as simple as possible when using the framework.I first thought about asking this on SO but it somehow feels like a bug within CoreStore to me as everything works except for the
.itemsproperty update. Thanks in advance for any help or clarification.For reference here are my classes:
WordPool
WordPoolItem
Here's a screenshot of my data model:
The delete rules are 'Cascade' on the side of
WordPooland 'Nullify' on the side ofWordPoolItem.I'm also willing to invite you to the project so you can investigate the issue directly within the project if you like. Just send me an email in that case (see my profile).
@JohnEstropia commented on GitHub (Jan 22, 2016):
@Dschee I believe this is because you are extracting objects out of their transaction scope:
The MOC for the wordPool you returned already expired, and the behavior from then on is undefined.
Also, I don't think this does what you expect it to:
This fetches an object from the main context, so you can't use this object instance inside transactions like so:
These mistakes are easy to make when doing operations via the NSManagedObject instead of executing from the data stack/transactions directly, so CoreStore doesn't encourage the pattern. I suggest avoiding methods that are vague in read/write usage. Otherwise, just create a transaction with
CoreStore.beginUnsafe()and use it globally (never use CoreStore.xxx methods).@Jeehut commented on GitHub (Jan 23, 2016):
Thank you for your answer, @JohnEstropia. I actually like how this library is designed (which is why I'm using it in favor of others) but my goal is to abstract away from the implementation of how my data is saved within my framework so that I can change the implementation at all times without the need to change the usage of it in apps. So that's why I opted for the above solution which is both easy to understand and use (e.g.
WordPool.create(name: "NewWordPool")) but still abstracts away from the fact that CoreStore or even CoreData is used at all.I'm not sure though what you were referring to when you said:
Is there another way of abstracting away from the implementation + keeping usage simple and at the same time not use NSManagedObject instances and passing them around? If there is, I'd be glad to rethink my approach. But passing a stack / transaction to the app that is using my data storage framework and calling methods like
commitfrom there is not an option as this would disclose unnecessary implementation details (in my opinion).In any case, I just changed my code to fix the issues you mentioned, now not only my tests for the
destroymethod fail, but also the ones forupdate(...). Here's my new create and update methods:WordPool
WordPoolItem
Seems like I'm still not using this correctly. I thought the issue was that I called fetchExisting after the
beginSynchronousclosure was closed. Also I removed returning anything fromupdateas you stated that returning self would be sufficient (and as returningselfwould be redundant, I just removed it completely). What is my misconception?@JohnEstropia commented on GitHub (Jan 26, 2016):
First, about your code:
WordPool.create()
I suggest you only call
fetchExisting()on the same queue you'll use the instance on. Use the same pattern for your WordPoolItem.create()WordPool.update()
Your WordPool and WordPoolItem's
update()looks fine, but you might need to re-fault the object right afterbeginSynchronous(). This might also fix yourdestroy()method:About the architecture, it was a conscious decision to avoid adding utility methods that abstract away the separation between DataStack and Transaction operations. I used to use MagicalRecord before, which implements such methods as your
WordPool.create(), but I found it's too easy to make mistakes such as mixing objects from different MOCs, or using objects from the wrong threads.Since you want to bypass transactions (you're just doing things synchronously, which will cause you deadlocks at some point), I suggest you just use a global
UnsafeDataTransactionand do everything from there. I'll think about lettingUnsafeDataTransactions create their ownListMonitors andObjectMonitors.@JohnEstropia commented on GitHub (Feb 2, 2016):
I'm closing this as it's more of an architecture problem and not a bug in CoreStore (the unit test includes object deletion). If you have any other questions feel free to message anytime :)