Entity Framework after save event - entity-framework

Is there a SaveChanges event that fires after changes are saved, but before the change tracker is updated?
I am using EF 6.
I need to perform a task whenever the status changes on a certain entity.
I have overridden SaveChanges to set this up. I can use ChangeTracker to tell what changes. When it's the correct entity with the correct change I fire of my code.
After the base SaveChanges is called, ChangeTracker no longer shows the entity as modified, so I need to do my task just before I save. However, there is a chance that SaveChanges will fail and I should not have done my task.
How can I hook into the ChangeTracker after the save, but before the model and ChangeTracker is updated?

Can you override the save changes method?
//you will use a different dbcontext name than faroutEntities5
public partial class faroutEntities5 : DbContext
{
public faroutEntities5()
: base("name=faroutEntities5")
{
}
public override int SaveChanges()
{
ChangeTracker.Entries()....
return base.SaveChanges();
}
...

Related

When using JPA entityManager why do you have to merge before you remove?

For a while now I have been wondering why when using JPA, do I have to write my delete methods like this:
#Transactional
public void delete(Account account)
{
if (entityManager.contains(account))
{
entityManager.remove(account);
}
else
{
entityManager.remove(entityManager.merge(account));
}
}
Perhaps the contains isn't needed since the transaction begins and ends with this method, but I still wonder why the remove couldn't just take an unmanaged object. Is it because it needs to be managed in order to know what the id is for that object? Any other insights would be great to hear. I just want to understand the hows and whys of the JPA remove.
The remove operation can be cascaded to associations of an entity.
To be able to know which associated entities to remove, the entity manager can't rely on a detached entity, since, by definition, this detached entity doesn't reflect the latest state of the entity, and doesn't necessarily have all its cascaded associations recursively loaded.
So, if it accepted a detached entity, remove() would have to decide for you: either merge the detached entity and execute the remove operation based on what the detached entity contains, or simply load the entity having the same ID as the detached entity, and execute the operation based on the loaded entity.
Instead of deciding for you, it simply requires an attached entity. That way, you decide what you want.

EF Code First - How does it know which objects to update?

As in the title, I have a method:
void method(MyDb db, Thread thread, Post post)
{
thread.Title = "changed";
db.SaveChanges();
}
(of course thread item is within MyDb object)
How does it recognize items that need to be updated? I didn't specify anywhere anything like db.Update(thread) or anything like that, it knew what to update without my help. What mechanisms are under it?
When you load entity Thread from database it becomes by default "attached". It means EF internally keep reference to your entity and it also keeps original values of the entity when you loaded it from the database.
When you updated a title there may be two scenarios:
You are using change tracking proxies and EF was notified about your change so it now knows that your instance was modified and it applies those changes to database when you call SaveChanges
You are not using change tracking proxies and when you call SaveChanges EF goes through its internally maintained list of entity references and check if any entity has any property different from original values - all such entities and their modified properties are updated to database during SaveChanges
You can read more about that process here.

Repository pattern with EF4 CTP5

I'm trying to implement the repository pattern with ef4 ctp5, I came up with something but I'm no expert in ef so I want to know if what I did is good.
this is my db context
public class Db : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
}
and the repository: (simplified)
public class Repo<T> : IRepo<T> where T : Entity, new()
{
private readonly DbContext context;
public Repo()
{
context = new Db();
}
public IEnumerable<T> GetAll()
{
return context.Set<T>().AsEnumerable();
}
public long Insert(T o)
{
context.Set<T>().Add(o);
context.SaveChanges();
return o.Id;
}
}
You need to step back and think about what the repository should be doing. A repository is used for retrieving records, adding records, and updating records. The repository you created barely handles the first case, handles the second case but not efficiently, and doesn't at all handle the 3rd case.
Most generic repositories have an interface along the lines of
public interface IRepository<T> where T : class
{
IQueryable<T> Get();
void Add(T item);
void Delete(T item);
void CommitChanges();
}
For retrieving records, you can't just call the whole set with AsEnumerable() because that will load every database record for that table into memory. If you only want Users with the username of username1, you don't need to download every user for the database as that will be a very large database performance hit, and a large client performance hit for no benefit at all.
Instead, as you will see from the interface I posted above, you want to return an IQueryable<T> object. IQuerables allow whatever class that calls the repository to use Linq and add filters to the database query, and once the IQueryable is run, it's completely run on the database, only retrieving the records you want. The database is much better at sorting and filtering data then your systems, so it's best to do as much on the DB as you can.
Now in regards to inserting data, you have the right idea but you don't want to call SaveChanges() immediately. The reason is that it's best to call Savechanges() after all your db operations have been queued. For example, If you want to create a user and his profile in one action, you can't via your method, because each Insert call will cause the data to be inserted into the database then.
Instead what you want is to separate out the Savechanges() call into the CommitChanges method I have above.
This is also needed to handle updating data in your database. In order to change an Entity's data, Entity Framework keeps track of all records it has received and watches them to see if any changes have been made. However, you still have to tell the Entity Framework to send all changed data up to the database. This happenes with the context.SaveChanges() call. Therefore, you need this to be a separate call so you are able to actually update edited data, which your current implementation does not handle.
Edit:
Your comment made me realize another issue that I see. One downfall is that you are creating a data context inside of the repository, and this isn't good. You really should have all (or most) of your created repositories sharing the same instance of your data context.
Entity Framework keeps track of what context an entity is tracked in, and will exception if you attempt to update an entity in one context with another. This can occur in your situation when you start editing entities related to one another. It also means that your SaveChanges() call is not transactional, and each entity is updated/added/deleted in it's own transaction, which can get messy.
My solution to this in my Repositories, is that the DbContext is passed into the repository in the constructor.
I may get voted down for this, but DbContext already is a repository. When you expose your domain models as collection properties of your concrete DbContext, then EF CTP5 creates a repository for you. It presents a collection like interface for access to domain models whilst allowing you to pass queries (as linq, or spec objects) for filtering of results.
If you need an interface, CTP5 doesn't provide one for you. I've wrapped my own around the DBContext and simply exposed the publicly available members from the object. It's an adapter for testability and DI.
I'll comment for clarification if what I said isn't apparently obvious.

Entity Framework - Code First, DbSet.Local Not Updating in UI

I have a Code First, CTP5 data context. I have a WPF app with a DataGrid. I set its DataContext like:
dataGrid.DataContext = _context.Customers.Local;
then I add a few entities using
_context.Customers.Add(customer1); and so on
_context.SaveChanges();
Then, I give these customers (a list of the customers) to another class to do some work on them.
customerUpdater.Update(customers);
That takes a long time and it updates properties of each customer while it's working. e.g.
foreach(var customer in customers) { customer.Name = "updated name"; }
I'm not seeing those updates in my WPF UI though! All I see are the original list of unaltered customers. Customers.Local is an ObservableCollection though, so I don't understand why I'm not seeing the updates in the UI.
I don't want to call SaveChanges() every time a property update occurs, it would be nearly constantly. Can someone tell me why this won't update?
If Customers.Local is an observableCollection, and you update the property "name" of one of their items, you are not seeing the updates because you are not modifying the observable collection, what you are modifying is the value of a property of one of the items (customer) present in the observableCollection, but the observableCollection will not send any notifications to the UI because it remains unchanged (it has the same number of items)
If you want the UI to be notified when you update the property name of a customer, you have to make the customer class to implement the INotifyPropertyChanged interface.
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

JPA - saving changes without persist() invoked

We are using Toplink implementation of JPA + Spring + EJB. In one of our EJBs we have something like this:
public void updateUser(long userId, String newName){
User u = em.get(User.class, userId);
u.setName(newName);
// no persist is invoked here
}
So, basically this updateUser() method is supposed to update the name of a user with the given userId.
But the author of this method forgot to invoke em.persist(u).
And the strangest thing is that it works fine. How can it be? I was 100% sure that
without invoking em.persist() or em.merge() there is no way that changes could have been saved into database. Could they? Is there any scenario when this could happen?
You're working with a managed entity. If the entity does not become detached because its entity manager is closed, all changes done to the entity are reflected to the database when the session is flushed/closed and the transaction commited.
From the Java EE tutorial:
The state of persistent entities is
synchronized to the database when the
transaction with which the entity is
associated commits.
Edit for clarity and explanation: So there are three distinct modes that an entity could be in during its lifecycle:
Unsaved: The entity has been instantiated, but persist() has not been called yet.
Managed: The entity has been persisted using persist(), or loaded from the database, and is associated with an entity manager session. All changes to the entity are reflected to the database when the entity manager session is flushed.
Detached: The entity's entity manager session was closed. Changes to the entity will not be reflected to the database automatically, but can be merged explicitly using the merge() command.