I'm using AFIncrementalStore to connect my iOS application to my REST API. When I load my initial view controller, I create an NSFetchRequest that loads the latest 100 Events (NSManagedObjects) into view. The problem is that each Event has a 1:1 relationship with a Group object, and as soon as the Event is loaded, the incremental store is asked to fill that Group object, which in my case triggers an individual request to the server for each of the 100 Events.
I can see a couple ways to solve this problem, such as not requesting Groups from the server if they are already saved locally, caching the network request, or not storing the relationship in the NSManagedObject. But ideally, the Group object could start out as a Fault and only request to be filled once one of its field is accessed, similar to what happens with one-to-many relationships. Unfortunately I can't find any documentation that says how to force a one-to-one relationship in core data to be lazy-loaded. Is it possible?
Maybe this is what you are looking for?
From AFIncrementalStore.h:
/**
Returns whether the client should fetch remote relationship values for a
particular managed object. This method is consulted when a managed object
faults on a particular relationship, and will call
`-requestWithMethod:pathForRelationship:forObjectWithID:withContext:` if `YES`.
#param relationship The relationship of the specifified managed object
#param objectID The object ID for the specified managed object.
#param context The managed object context for the managed object.
#return `YES` if an HTTP request should be made, otherwise `NO. */
- (BOOL)shouldFetchRemoteValuesForRelationship:(NSRelationshipDescription*)
relationship forObjectWithID:(NSManagedObjectID *)objectID
inManagedObjectContext:(NSManagedObjectContext *)context;
If so, you could set this with
- (BOOL)shouldFetchRemoteValuesForRelationship:(NSRelationshipDescription *)relationship forObjectWithID:(NSManagedObjectID *)objectID inManagedObjectContext:(NSManagedObjectContext *)context
{
return NO;
}
in your AFRESTClient <AFIncrementalStoreHTTPClient> subclass.
I've been struggling this as well. Looks like one-to-one relations will always be eager loaded. One way around this could be to declare it as a one-to-many relation so that it automatically does a lazy load instead. Then in your model class, you can have a method that returns the first one in the set.
Related
I have a managed object lets say products and I have another object that getting the data from another server and is already stored as managed object. There's nothing you in terms of the JSON data you get from the server that you can relate the two objects together. The only way is to do it manually before you get send the request. Is there a way to create a relationship that can do that using Restkit?
If you have the unique identifier of the source object in the request path or somewhere in the response body then you can use it in the mapping and perform a foreign key mapping to connect a relationship between the source and response objects.
If the identity is in the request path then you need to use RKRoute to prepare the request and #metadata.routing.parameters in your mapping to extract the identity. If it's in the response body then the standard mapping approach applies.
Once you have it, you map it into a temporary attribute on your destination object.
Once you have that you can perform your foreign key mapping.
I'm developing an application with Domain Drive Design approach. in a special case I have to retrieve the list of value objects of an aggregate and present them. to do that I've created a read only repository like this:
public interface IBlogTagReadOnlyRepository : IReadOnlyRepository<BlogTag, string>
{
IEnumerable<BlogTag> GetAllBlogTagsQuery(string tagName);
}
BlogTag is a value object in Blog aggregate, now it works fine but when I think about this way of handling and the future of the project, my concerns grow! it's not a good idea to create a separate read only repository for every value object included in those cases, is it?
anybody knows a better solution?
You should not keep value objects in their own repository since only aggregate roots belong there. Instead you should review your domain model carefully.
If you need to keep track of value objects spanning multiple aggregates, then maybe they belong to another aggregate (e.g. a tag cloud) that could even serve as sort of a factory for the tags.
This doesn't mean you don't need a BlogTag value object in your Blog aggregate. A value object in one aggregate could be an entity in another or even an aggregate root by itself.
Maybe you should take a look at this question. It addresses a similar problem.
I think you just need a query service as this method serves the user interface, it's just for presentation (reporting), do something like..
public IEnumerable<BlogTagViewModel> GetDistinctListOfBlogTagsForPublishedPosts()
{
var tags = new List<BlogTagViewModel>();
// Go to database and run query
// transform to collection of BlogTagViewModel
return tags;
}
This code would be at the application layer level not the domain layer.
And notice the language I use in the method name, it makes it a bit more explicit and tells people using the query exactly what the method does (if this is your intent - I am guessing a little, but hopefully you get what I mean).
Cheers
Scott
I've learned that entities are classes that represent the tables inside a database schema. But on this link they speak of an entity being tracked (attached) by the context
http://msdn.microsoft.com/en-us/data/jj592676.aspx
Added: the entity is being tracked by the context...
Do they speak of the objects/instances of entity's (so the classes) getting tracked by Entity Framework? Or literally the entity itself? I'm confused.
In one of my webapplications I am using this code, does it say all instances of FinalStudyDecision are in the modified state, or just the object fsd?
context.FinalStudyDecisions.Attach(fsd);
context.Entry(fsd).State = EntityState.Modified;
Or does this code just do it for one single object?
ObjectStateManager.ChangeObjectState(fsd, EntityState.Modified);
When an entity is attached to a context, the context "knows" the object and starts tracking its changes.
Normally, an entity is attached to a context when it is fetched from the database, e.g. by context.FinalStudyDecisions.Single(x => x.Id == 1) (if there is an item with Id == 1 of course).
But if you've got an existing FinalStudyDecisions that is not known by a context you can use the Attach method to make it known. This usually happens when an object is serialized to and subsequently deserialized from a web client.
If you attach an object to a context its state (EntityState) is Unchanged, so often you will change its state to Modified when you receive it back from a web client. This will trigger EF to store the object when SaveChanges is called.
Both
// DbContext API
context.Entry(fsd).State = EntityState.Modified;
and
// ObjectContext API
ObjectStateManager.ChangeObjectState(fsd, EntityState.Modified);
only change the state of the fsd object.
Important: if you Add an object to a context, either by setting its state Added or by adding it to a DbSet (or ObjectSet), not only fsd but also all its child objects are changed to Added.
I'm designing my first project using Core Data (for iPhone) and Im having some issues that might be related with my design approach.
I'm doing an application that allows the user to create an Order (let's say for a restaurant).
I'm using the graphic designer to model my persistence object (i.e. OrdeMO). I add MO to the ead of each name to indicate its a Managed Object.
I use XCode to create the Managed Object Class automatically.
I have created some "DAO" classes that allows you to search or create a new object in the Managed Context.
Now to my problem.
I want to create an OrderMO object to store the order the user is creating, BUT I don't want it to be part of the context until the user actually places it.
I tried creating the object with [OrderMO alloc] but the object I get is "incomplete" and when I try to set any of its attribute I get an error.
I'm assuming the problem is that I need to create the order IN the context in order to use it. Is that so?
I have considered various options:
Create the object in the context and the user rollback if the user discards the order. The problem is that the user might save other context object during the process (like his prefs) so this doesn't work. Is there a way to create the object "inside a separate transaction" of sorts?
Create a wrapper object that will hold the same data as the MO, and then only create the MO when the user place the order. The downside of this is that I have to maintain a new class.
Create an attribute in the MO, such as "placed", and use to filter my searches in the context. The problem with this one is that I will end up with "trash" objects in the domain (i.e. unplaced orders) and I will have to do some cleanup from time to time...
Do I have any other choice?
Any suggestion is appreciated.
Thanks (for reading this long post!)
Gonso
You should create the OrderMO object in the managed object context and then delete it if the user decides not to place the order.
If the context is saved before the object is deleted, the "trash" object will be deleted from the persistent store on the next save (if the context wasn't saved, the "trash" object will never be saved to the persistent store).
The flag to determine if the order was placed or not does not have to live in the OrderMO object as you suggest in option 3. It could be in the view controller that is tracking the order(s) that are being edited. And, again, you won't have "trash" objects because they will have been deleted.
I want to follow the DDD philosophy and not access entity objects of an aggregate directly. So, i have to call the root object to get the associated entity. But In other cases I dont always want every associated entity to load when the root is called. Is that the purpose of lazy loading?
How do I access entity objects through the root without loading all the associated objects everytime if i disable lazyloading feature of linq?
EDIT:
For example, If I have a Person as the Root Entity, and the Person has Name, Addresses and OwnedProperties. If I want to get a list of People so that I could display their names, I dont necvessarily want to load up Owned Properties every time on the call to the Repository. Conversely, on another page I may want to show a list of OwnedProperties, but do not want the other information to load with the call. what is the simple way of just calling the Person without the owned property entity other than creating a new person object without that owned properties?
I don't thinks that's possible without lazy loading.
Getting all data at once: Eager Loading
Getting data when accessed: Lazy Loading
According to your edit:
What I do in these situations, is create a 'View' class or a 'DTO' class which just contains the properties that I'm interested in.
For instance, I could have a 'PersonView' class which just has a Name property for instance.
Then, using my OR/M mapper (I use NHibernate), I create a HQL query (or Criteria query) which works on my 'Person' entity. Before I execute the query, I tell NHibernate that I want 'PersonView' objects as a result (I specify a projection). Then, NHibernate is smart enough to execute a query that only retrieves the columns that are necessary to populate the PersonView instances.
One way to avoid lazy loading is just using the object 'id'