What are the benefits of using attached objects vs detached objects?
What I'm currently doing in my repository is manually detach my objects before i update or delete them. So if I'm updating or deleting, I do not do a round trip but I delete by ID. I think working with detached scenario works for me. Am I doing something wrong?
I'm working with an n-teir app that utilizes asp.net mvc and wcf.
Using attached objects will allow you to manipulate, track changes, do concurrency optimization. In most cases I use attached objects for updates or in a stateful application. This will also allow you to have lazy-loading and to benifit from the context cache. If you are using entity framework in a statefull manner, this is great because you can reduce the number of calls to the database when you require a single object from the context. Using the GetObjectByKey will query the context before making a query to the database. if the object was previously loaded, it will save you a round trip to the database.
Using detached objects are great! it allows for faster reads, simpler objects to materialize, a smaller memory footprint for the entity context. It is also best when sending data over the wire (wcf.. services). Anything out of scope, or even when you are converting the objects to domain objects. Since you do not require any tracking on the objects, this is a good optimization to start with. This can be acheived quickly using the NoTracking merge option on the entity set.
Detached objects will also greatly simplify working with EF in environments where you have many instances of your context. Simply attach the object before making changes and saving.
Note: using NoTracking will not allow you to use lazy-loading, change tracking, GetObjectByKey or any of the statefull functionalities of entity framework. Using NoTracking you will need to use eager loading ("Include()") to load related entities / navigation properties. EntityKeys will also not be loaded.
Edit:
Lazy-loading on detached entities, does not work because it does not have a context to refer to for its queries. The entity may also be missing the required proxies and entitykeys.
I would greatly suggest using eager loading. This may also be an optimisation in the end because it is hard to guage the impact of lazy-loading. Because it can produce situations where if you are iterating a collection, it will make a request to the database for each object in the collection. This can be quite problematic when you have large collections.
entity.User.Attach(model);
entity.ObjectStateManager.ChangeObjectState(model,System.Data.EntityState.Modified);
entity.SaveChanges();
return View(model);
Related
I'm currently building a Core Data app and I've hit a snag. I guess here's some context on the schema:
The app is to keep track of a therapist's session with her clients. So the schema is organized thus: there's a table of clients, clients have sessions, sessions have activities, and activities have metrics. In the app these metrics translate to simple counters, timers, and NSSliders.
The crux is that the client wants to be able to insert previously made activities into new sessions for new clients. So, I've tried just doing a simple fetch request and then moved on to an NSFetchedResultsController. I keep running into the issue that since Core Data is an object graph, I get a ton of activity entries with virtually the same data. The only differentiating property would be whatever the session is (and if you want to go further back, the client itself).
I'm not sure if this is something I need to change in the schema itself, or if there's some kind of workaround I can do within Core Data. I've already tried doing distinct fetch results with the NSFetchedResultsController by using the result type NSDictionaryResultType. It kind of accomplishes what I want but I only get the associated properties of the entity, and not any children entities associated with it (I need those metrics, you see).
Any help is appreciated, and I can post code if desired even though I don't really have a specific coding error.
I don't see the problem. If you modeled things with the Client, Session, Activity, and Metric entities, each having a to-many relationship to the one to its right and to-one/to-many inverse relationship to the one to its left (in the order I listed the entities), there is nothing stopping you from adding a particular activity into another session (of another client), is it?
Maybe I'm misunderstanding the question.
Just use a simple NSFetchRequest and set the predicate for exactly what you are looking for. You can set the fetch limit if you are getting too many results but your question doesn't exactly sounds like a question IMO.
I believe what you are looking for is an NSPredicate to narrow your results down. Once you fetch a specific object you can assign any relation or attribute to that object easily with dot notation then save the context.
I am creating an app that requires "offline" persistence of it's data that is exposed via an OData web service. The OData service gives me access to all the tables of the underlying database, as well as all the relevent database fields such as ID's.
Additionally, I already have a SQLite database schema that I can use.
My question, and to which I have flip-flopped on twice already, is whether it is better to store the web service data on the device via SQLite directly (using FMDB), or to leverage Core Data?
If I use Core Data, then I lose the relational benefits of Primary and Foreign keys, but gain the benefit of automatically nested/populated NSManagedObjects. I'm not totally sure of how best to recreate the relational nature of my data objects.
If I use SQLite, I can just straight insert/update the results of the web service calls, and automatically get relationships from existing Foreign Key columns. The downside is I probably need to manually encapsulate my results in POCO objects.
My gut right now is telling me SQLite, but it seems as though the community overwhelmingly points to Core Data in any/all cases. If Core Data, how do I best create and maintain object relationships (especially when they are 1->many)
This app will not go into the app store, if any Apple-happy aspects are of issue.
Core Data models relationships directly. So in your schema you might say e.g. that object A has a relationship with object B and that the relationship is 'to many'. However the relationships work like normal object references — you need to link each instance of A to all relevant instances of B, you don't [easily, or usually] just say 'A relates to B through foreign key bID' and then have the relationship deal with itself.
If you have a SQL persistent store then the way that's implemented is that each object gets an implicit unique key for its table. Relationships are modelled as an extra column that holds the key or keys of every linked object in the foreign table.
Other things people tend not to like about Core Data:
if you rely consistently on the implicit data fetches then you'll often get poor performance, so you often end up with explicit queries anyway in order to populate results you're probably about to look at in a single database trip;
since SQLite is not thread safe and Core Data objects maintain a live connection to their stores, Core Data objects are not thread safe (though objectID references to them are and you can fetch similarly safe dictionaries instead of live objects if you prefer);
even once you've otherwise solved the threading issue, saves in the background still block accesses in the foreground as per the SQLite thread safety comment.
Conversely:
since iOS 5 you can use NSIncrementalStore so that you just run Core Data queries and your Core Data store is smart enough to go to the server if it needs to — the main body of your code has no idea of whether data is local or remote and doesn't need to repeat itself when declaring what it's going to look for;
you get the live database connection for free, so your objects automatically update themselves if the persistent store changes;
if you're looking mainly to do iPhone-style table views then the work is almost entirely done for you already, you pretty much just supply the query;
Core Data has a sophisticated system of faulting that largely resolves memory footprint issues when dealing with large data sets.
I've got an application that stores products in a Core Data file. These pruducts include images as "Transformable" data.
Now I tried adding some attributes using Lightweight migration. When I tested this with a small database it worked well but when I use a really large one with nearly 500 MB the application usually crashes because of low memory. Does anybody know how to solve this problem?
Thanks in advanced!
You'll have to use one of the other migration options. The automatic lightweight migration process is really convenient to use. But it has the drawback that it loads the entire data store into memory at once. Two copies, really, one for before migration and one for after.
First, can any of this data be re-created or re-downloaded? If so, you might be able to use a custom mapping model from the old version to the new one. With a custom mapping model you can indicate that some attributes don't get migrated, which reduces memory issues by throwing out that data. Then when migration is complete, recreate or re-download that data.
If that's not the case... Apple suggests a multiple pass technique using multiple mapping models. If you have multiple entity types that contribute to the large data store size, it might help. Basically you end up migrating different entity types in different passes, so you avoid the overhead of loading everything at once.
If that is not the case then (e.g. the bloat is all from instances of the same entity type), well, it's time to write your own custom migration code. This will involve setting up two Core Data stacks, one with the existing data and one with the new model. Run through the existing data store, creating new objects in the new store. If you do this in batches you'll be able to keep memory under control. The general approach would be:
Create new instances in the new model and copy attributes only. You can't set up relationships yet because related objects might not exist in the new data store. Keep a mutable dictionary mapping NSManagedObjectIDs from the old store to the new one, for use in the next step. To keep memory use low:
As soon as you have created a destination store object, free up the memory for the source object by using refreshObject:mergeChanges with NO for the second argument.
Every 10 instances (or 50, or whatever) save changes on the destination managed object context and then reset it. The interval is a balancing act-- do it too often and you'll slow down unnecessarily, do it too rarely and memory use rises.
Do a second pass where you set up relationships in the destination store. For each source object,
Find the corresponding destination object, using the object ID map you created
Run through the source object's relationships. For each one, find the corresponding destination object, also using the object ID map.
Set the destination object's relationship based on the result.
While you are at it consider why your data store is so big. Are you storing a bunch of binary data blobs in the data store? If so, make sure you're using the "Allows external storage" option in the new model.
I have an old SL4/ria app, which I am looking to replace with breeze. I have a question about memory use and caching. My app loads lists of Jobs (a typical user would have access to about 1,000 of these jobs). Additionally, there are quite a few lookup entity types. I want to make sure these are cached well client-side, but updated per session. When a user opens a job, it loads many more related entities (anywhere from 200 - 800 additional entities) which compose multiple matrix-style views for the jobs. A user can view the list of jobs, or navigate to view 1 job at a time.
I feel that I should be concerned with memory management, especially not knowing how browsers might deal with this. Originally I felt this should all be 1 EntityManager and I would detachEntities when user navigates away from a job, but I'm thinking this might benefit from multiple managers by intended lifetime. Or perhaps I should create a new dataservice & EntityManager each time the user navigates to a new hash '/#/' area, since comments on clear() seems to indicate that this would be faster? If I did this, I suppose I will be using pub/sub to notify other viewmodels of changes to entities? This seems complex and defeating some of the benefits of breeze as the context.
Any tips or thoughts about this would be greatly appreciated.
I think I understand the question. I think I would use a multi-manager approach:
Lookups Manager - holds once-per session reference (lookup) entities
JobsView Manager - "readonly" list of Jobs in support of the JobsView
JobEditor Manager - One per edit session.
The Lookups Manager maintains the canonical copy of reference entities. You can fill it once with a single call to server (see docs for how). This Lookups Manager will Breeze-export these reference entities to other managers which Breeze-import them as they are created. I am assuming that, while numerous and diverse, the total memory footprint of reference entities is pretty low ... low enough that you can afford to have more than one copy in multiple managers. There are more complicated solutions if that is NOT so. But let that be for now.
The JobsView Manager has the necessary reference entities for its display. If you only displayed a projection of the Jobs, it would not have Jobs in cache. You might have an array and key map instead. Let's keep it simple and assume that it has all the Jobs but not their related entities.
You never save changes with this manager! When editing or creating a Job, your app always fires up a "Job Editor" view with its own VM and JobEditor Manager. Again, you import the reference entities you need and, when editing an existing Job, you import the Job too.
I would take this approach anyway ... not just because of memory concerns. I like isolating my edit sessions into sandboxes. Eases cancellation. Gives me a clean way to store pending changes in browser storage so that the user won't lose his/her work if the app/browser goes down. Opens the door to editing several Jobs at the same time ... without worrying about mutually dependent entities-with-changes. It's a proven pattern that we've used forever in SL apps and should apply as well in JS apps.
When a Job edit succeeds, You have to tell the local client world about it. Lots of ways to do that. If the ONLY place that needs to know is the JobsView, you can hardcode a backchannel into the app. If you want to be more clever, you can have a central singleton service that raises events specifically about Job saving. The JobsView and each new JobEditor communicate with this service. And if you want to be hip, you use an in-process "Event Aggregator" (your pub/sub) for this purpose. I'd probably be using Durandal for this app anyway and it has an event aggregator in the box.
Honestly, it's not that complicated to use and importing/exporting entities among managers is a ... ahem ... breeze. Well worth it compared to refreshing the Jobs List every time you return to it (although you'll want a "refresh button" too because OTHER users could be adding/changing those Jobs). You retain plenty of Breeze benefits: querying, validation, change-tracking, batch saves, entity navigation (those reference lists work "for free" in Breeze).
As a refinement, I don't know that I would automatically destroy the JobEditor view/viewmodel/manager when I returned to the JobsView. In my experience, people often return to the same Job that they just left. I might hold on to a view so you could go back and forth quickly. But now I'm getting tricky.
I'm syncing with a MySQL database.
Initially, I was going to loop through all my new/modified objects and set all the foreign keys for that object and then do the next object, and so on... But that's a lot of fetch requests.
So instead I wanted to loop through all my new/modified objects and set the foreign keys one at a time. So the first pass over my objects sets fk1, my next sets fk2, so on...
Cool, fetch requests drastically reduced. Now I'm curious if I could thread these fk setters. They aren't dependent on each other, but they are modifying the same object, even though they're only setting one relationship, and it's a different relationship. Speaking in git terms, these changes could be 'merged' together without any conflict, but is it possible to push changes in one child managedObjectContext(childContext:save) up to the parentManagedObjectContext(parent:performBlock^{parent:save}) and pull it down in another, different child managedObjectContext(???)? Or will the merge policy only take one childContext's version of the object and leave the other fks effectively unchanged.
I know this exists: NSManagedObjectContext/refreshObject:mergeChanges:
But that's on an object by object level. Will that cause a bunch of fetches? Or will that update my whole context at once/in batches?
Following Apple's suggestion from here:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html
I've created/updated my values before I start setting any relationships, so all entities already exist before I try to point any relationships at them.
Aside: We have a couple apps that could benefit from the concurrency, because they throw a considerable amount of data around, and with the quad core iPad apps, this would really help out with the time the initial sync takes.
I'n not sure what you are trying to do and why (you could write less lines in your question and be more clear), but here are some guidelines for working with Core Data:
-- NSManagedObjectContext is not thread safe. Therefore, you need to limit your access to this managed object context to happen inside 1 thread. Otherwise, you may end up having many errors you can't understand.
-- NSManagedObjectContexts apart from doing other things, serve like "snapshots" of your persistent store. That means that when you change an object, you save it to the persistent store, you post a NSManagedObjectContextDidSaveNotification and then call mergeChangesFromContextDidSaveNotification: in another place inside your program in order to load the latest data from the persistent store. Be careful of thread safety.
NSManagedObjectContext/refreshObject:mergeChanges: according to apple is not about just refreshing a managed object. If you pass YES as the second argument, it will write any pending changes from this managed object context to the persistent store, and will load any other changes to other properties of this object from the persistent store, thus "synchronizing" your object with the persistent store. If you pass NO as the second argument, the object loses any pending changes, and it is being turned to a fault. That means that when you attempt to access it, the Managed Object Context will reload the object as it was last saved to the database. It will NOT reload the entire managed object context. It will only operate on the object.
Aside: I have written a blog post that scratches the surface of asynchronous loading from a core data database. In my case, since I'm doing heavy lifting with the database, I ended up using an NSOperation that operates with its own NSManagedObjectContext, and using serial GCD queues to save large chunks of data, since it was faster than having multiple threads accessing the same persistent store, even if they operate on different managed object contexts.
I hope I helped.