I am using EF 4.1 and in a certain point in my application, I read all the data satisfying a condition from an entity by performing:
context.Entity.Where(<condition>)
then, I iterate over them through a loop, and in specific situations I store some of them into a Dictionary (key value is the Id of the entity, and value is the entire object).
Later, in another point of my app, I read all the objects stored in the dictionary and I update them.
After updating them, I perform SaveChanges on the context, (the context is the same that was used when reading the entire entity and when items where stored in the dictionary.
So at this point, I would like to know if when I perform the savechanges, the data is sent to the database and udpated correctly since I am not sure as the objects modified come from the dictionary and I do not know if EF is so intelligent to know it should update database.
The dictionary as well as the EF context hold references to the objects. As long as the context isn't disposed, it will be able to track the changes.
In other words, putting your entities in a Dictionary (or List or any other means of collection) has no influence on the entities and their context.
Related
I'm a bit confused about how to use the lists returned from a ToList in EF6. If I bind the list to a CollectionViewSource I can easily view the objects returned. However, I consider these objects somewhat disconnected from the data that EF tracks in memory such that if I edit the objects in the list and then call SaveChanges, the edits won't be persisted back to the data store. For that reason, I have been binding to the DBSets .Local, making edits to these objects, and then calling SaveChanges.
Am I doing this right?
Those objects are not disconnected at all! Every modification you do to their properties will be persisted to the data store on a SaveChanges call.
Entity Framework works in such a manner that it loads one record once, and only once into one context. In other words, if you obtain an entity (say, through a Linq query) from the DbSet object, it will also appear in the Local collection, and it will be the very same object. Same thing applies to the results of ToList() functions; there is only one instance for one record in a context. At this point, i'm sure you say my first statement is evident.
Btw, your method (consequently) does the work as well.
Regards
I have several entities that contain datetime fields for EffectiveAsOf and ExpiredAsOf. When an entity is modified I want to override the SaveChanges method and rather than just update the existing entity have the code save the original record back to the database with an ExpiredAsOf datetime set to the current time, and a new record inserted with the new data and EffectiveAsOf set to the current time with ExpiredAsOf set to null.
I know that the ObjectStateEntry items in the objectStateEntryList contain CurrentValues and Original values objects, as well as an Entity object. What does EF use to write data to the DB the CurrentValues data or the Entity? How do I go about creating a new entry? Or, am I going about this the wrong way entirely?
I know that I can handle this in the entities outside of EF, but would rather have EF detect and handle these entities automatically.
Thanks in advance for your help and insight,
Jim
EF by default will use both - it uses original values to check for a concurrency issue (i.e. if the record has changed since you loaded the data from the DB) then uses the entity's current/modified values to update the DB record.
It is not possible to have EF "detect and handle these entities automatically". You will need to create a new instance of the entity object, copy the values from the existing entity object, set the appropriate effective and expired dates on both objects, add the new entity object to the DbContext, then save changes. The best place to do this is by overriding the SaveChanges() method of your DbContext. To keep it as clean and manageable as possible, I suggest using the repository pattern.
I have an app working with databases on both server side and iOS client side. And I use a HTTP services to sync between SQL Server on server side and Core Data on iPhone.
I have some Core Data objects like this:
ProductGroup
Attributes:
id
Relationships:
products
Product
Attributes:
id
productGroupId
Releationships:
productGroup
Due to the limit of the server, I can't use incremental sync. When I sync my data, (for example) I have to delete all ProductGroup objects, get response from server, then create new ones(and some old ones again).
The problem is, if I have a productA belongs to productGroupB, usually I can do productA.productGroup, but after I delete productGroupB and create another one with the same content, the relationship is lost.
So I am wandering is there any way to manage relationships by FKs, like the Entity Framework in .NET, so I can still find the object on the other end of the relationship after re-create.
You lose the relationship when you delete the ProductGroup objects because Core Data isn't SQL. In the case of relationships, Core Data cares nothing about the attributes of the object on the other side of the relationship, it just targets a specific object. You can have an arbitrary number of objects with the exact same attributes but different relationships and the objects will be completely distinct. A Core Data relationship is not an SQL join or key but a persisted pointer-like reference to a specific managed object. Delete the object and the pointer has to go as well.
To accomplish what you want, you could use a fetched property which would fetch on the Product.id attribute dynamically. However, that is a fairly clumsy way of doing things. You shouldn't have to resort to a fetched property in this instance.
I think you need to rethink your design. I have never seen a case where you had to delete an every instance of an entity/class just to add or remove objects. As a practical matter, you can't actually do that in one go. Instead you have to fetch the objects and then delete them one-by-one. You might has well check each object for if it needs to be deleted or updated while you are at it.
It sounds like you receive a great glob of SQL format data from the server and you think you have to build the object graph from scratch. You really shouldn't have to. You have to parse the data to create new ProductGroup objects anyway, so you should use the results of that parsing to alter the existing ProductGroup objects.
In pseudo-code it would look like:
Add a "synced" flag to ProductGroup entity in the data model
Set "synced" of every ProductGroup object to "false"
Extract data for a ProductGroup from server glob
Using data fetch for an existing ProductGroup object
If extracted data matches and existing ProductGroup object
update existing ProductGroup object
set synced of ProductGroup object to true
else
create new ProductGroup object with data
set synced of new ProductGroup object to true
Delete all ProductGroup objects where synced == false
The important thing to remember here is that you are dealing with objects and not tables, columns, rows or joins. People skilled in SQL often assume that Core Data is just an object wrapper around SQL. It is not. It is an object graph manager that may or may not use SQL far behind the scenes to persist (freeze dry) the object graph to disk.
You have to think in objects always. The intuitions you've developed for working with SQL are more likely to lead you astray than help you with Core Data.
I have a detached set of client objects that I'd like to update (I know they already exist in the db by primary key). Now I want to update them to the database. Knowing I need to query them first, I do so and now have to basically take the properties from the deattached objects and apply them to the attached objects. I finally call save changes. Is there a slick way to apply these properties from the detached collection to the attached one?
NOTE: The detached objects don't have the primary keys in them but I do have enough information to link with via a comparer class.
You don't need to do what you're doing. You can just call the Attach method on your ObjectContext to tell it that you want to work with your detatched objects. Then just call SaveChanges to update the database with your changed objects.
On the iPhone, Does Core Data have a way to bulk update a field for every instance of an entity that it's storing? Something like
update some_entities set some_count = 0 where some_count > 0
Or do I just have to instantiate every entity, set the value, then save it? (And if that's the answer, how could I do that in a single transaction, assuming the set is too large to fit in memory?)
This is not provided by Core Data, but you could use the makeObjectsPerformSelector:withObject: method of an NSSet or NSArray of your Core Data managed objects.
Pass the setter accessor as the selector and the value as the object.
For example, if the managed objects have an attribute "name" that needs to be set the same for all:
[[fetchedResultsController fetchedObjects] makeObjectsPerformSelector:#selector(setName:) withObject:#"name for all"];
You don't have to have an NSFetchedResultsController. You can use the array from an NSFetchRequest or even the NSSet from a to-many relationship among your Core Data entities.
Core Data isn't a database. If you want to bulk-update the objects, you'll have to fetch them and update the values yourself.
A good way of doing that would be to fetch, say, 100 at a time (using an NSFetchRequest with a fetchLimit set), update them, and then save the managed object context. Lather, rinse, repeat until all the objects are updated.
And, as gerry suggested, if the update you're doing is simple, you can use makeObjectsPerformSelector: to do the update in one line.
No, Core Data doesn't have a bulk update feature. If you're memory-constrained, you might consider redesigning your data model to simplify things; instead of storing an absolute count for each entity, track a master value for a group of entities and store a delta from that value per entity.
Core Data can definitely be frustrating at times for those of us used to thinking in SQL terms.