I'm using a repository implementation which is using a shared ObjectContext with other repositories. The repository holds an ObjectSet of the entities. I'm adding new entities via Add() method to the ObjectSet. While importing data I would like to query those fresh added objects to prevent duplicate data.
The ObjectContext implements a unit of work pattern. At the end of the import process I would like to call the commit method which calls context.SaveChange() to persist the data.
However, I couldn't find an easy way to query the freshly added entities before I called SaveChanges(). How do you guys handle such problems?
Query the ObjectStateManager.
var foo = context.ObjectStateManager
.GetObjectStateEntries(EntityState.Added)
.Select(s => s.Entity).OfType<Foo>().SingleOrDefault(f => f.Id == bar);
I used ObservableCollection inside repository.cs to get the data before saving it to database as below
public ObservableCollection<T> Local {
get { return UnitOfWork.GetContext().Set<T>().Local; }
}
if you want you can also use ICollection because it is a base class for observablecollection.
Now, you can query the repository as shown below...
Repository.Local.Where(x=>x.TrackingNumber == order.TrackingNumber).SingleOrDefault();
But, remember you cannot get data using Id's before saving to database so use some other unique field to get data. For further info click on the below link where similar kind of question was asked by me
Why I am not able to get recently added objects (yet to be saved in database) from repository
Related
It is possible to clear the Validation Results in an ObjectContext associated with an Entity Framework? What I wanted is something like this code:
public void ClearValidationResults (ObjectContext db)
{
var dbContext = new DbContext(db, true);
var validationResults = dbContext.GetValidationErrors();
validationResults.Clear();
}
I want to implement this functionality to use in unit tests to test the validation rules without to have to save changes in DataBase.
Thanks.
DbContext does not store validation errors, it validates entities each time you call DbContext.GetValidationErrors() or DbContext.SaveChanges(). So, if you have an invalid entity that is being tracked by your context DbContext.GetValidationErrors() will always return errors. You need to detach or fix the invalid entity/entities and the error will go away since there will be no invalid entities tracked by your context.
Clear Entity Local Storage.
When we adding Entity to Collection, its adding it to its Local Storage and we kept getting errors as the Local Storage of that Entity is not clear and still having old entries. So you Clear Entity Local rows.
dbContext.EntityName.Local.Clear();
I resolve the problem by creating a new ObjectContext object every time I need to clear the validation errors. Is not the most elegant solution but it works. Since this process is in the context of unit tests and the unit tests are fast enough, I will maintain this code until best solution arrived.
public void ClearValidationResults (ObjectContext db)
{
db = new MyObjectContext();
}
I have a WPF app that has a grid with a list of data that I loaded with EF. Some other window can make changes to the same data loaded on the grid but using a different dbcontext instance. How can I see the changed data on the grid? I know I can refresh a single entity with ctx.Entry<MyEntity>(instance).Reload(); - but I want to see all the changes and no matter what I do, I only see the old values. I can't use AsNoTracking neither create a new DbContext instance in this case.
To me looks like a very simple case and I cannot see why EF don't just
update the values of the entities.
EF has this mechanism as well but it is not exposed on DbContext API. You need to get back to ObjectContext. If you just want to reload set of entities you will call:
var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
objectContext.Refresh(RefreshMode.StoreWins, listOfEntitiesToReload);
RefreshMode.StoreWins causes all pending changes to be overwritten by reloaded values. You can also use RefreshMode.ClientWins which will keep your changes and merge them with reloaded data. The problem with this approach is that it only reloads entities you already have. You will not get new entities.
If you want to get new entities as well you must execute a query and you must tell EF that you want to reload values:
var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
var objectSet = objectContext.CreateObjectSet<MyEntity>();
objectSet.MergeOption = MergeOption.OverwriteChanges;
var result = objectSet.Where(...).ToList();
Again MergeOption.OverwriteChanges overwrites all pending changes but you can use MergeOption.PreserveChanges to merge reloaded values to your edited values.
I think there can be still some issues with refreshing values with some relations and maybe also entities which were deleted in the database.
I am attempting to update an existing record using JPA. The following link seems to suggest that the only way to update a record would be to write the update query for it
enter link description here
Which is fine. But again, I am wondering why am I pulling this out of stored proc to use all f the magic of open JPA?
I thought that If I had an instance of a JPA object that if I tried to persist to the database using a call similar to this
emf.persist(launchRet)
the JPA framework would check to see if the record allready exists, if so, it would then proceed to make the changes to that record, if not, it would just add a new record. Which would be really cool. Instead, I am going to have to end up writing all that logic myself in an update query. Which is fine, But why can't I just use a stored proc and just pass it all the necessary values?
UPDATE: CODE EXPLAINING WHAT MY LAST COMMENT IS ALL ABOUT
try{
launchRet = emf.find(QuickLaunch.class, launch.getQuickLaunchId());
if(launchRet==null){
emf.getTransaction().begin();
emf.persist(launchRet);
emf.getTransaction().commit();
}
else{
emf.refresh(launchRet);
}
}
The variable launch is passed into the method...
public QuickLaunch UpdateQuickLaunchComponent(QuickLaunch launch)
Would I simple just set the found launch launchRet equal to the launch that was passed in?
Read the link that you posted:
You can modify an entity instance in one the following ways:
Using an Updating Query
Using the Entity's Public API
[...]
The way used in 99% of the cases is the second way:
Foo someExistingFoo = em.find(Foo.class, someExistingFooId);
someExistingFoo.setSomeValue(theNewValue);
// no need to call any persist method: the EM will flush the new state
// of the entity to the database when needed
Of course, the entity can also be loaded via a query, or by navigating through the graph of entities.
If you have a detached entity, and you want to persist its state to the database, use the EntityManager.merge() method. It finds the entity with the same ID as the detached one passed as argument, copies the state from the detached entity to the attached one, and returns the attached one:
Foo attachedModifiedFoo = em.merge(detachedFoo);
If the detached entity isn't persistent (i.e. doesn't have any ID), then it is created and made persistent.
I want to create an integration test which grabs an EF entity from the DB, clones it to a detached object, modifies it and then saves it back and compares it again to the original.
However, I was using AutoMapper to create the clone of the class, but it turns out this is also tracked or an alias to the original object. I need it to be completely detached from EF, and am able to do this outside of my repository class (i.e. not using any EF detach methods).
The reason for doing this is my EF class contains nested collections of other classes and EF doesn't handle persisting the whole object tree. Hence, my Update() method in my repository class handles this and I want my NUnit test to test this code. I want the test is to be able to quickly create a copy of my original class without EF tracking it.
Creating a cloned object containing current, original, or database
values The DbPropertyValues object returned from CurrentValues,
OriginalValues, or GetDatabaseValues can be used to create a clone of
the entity. This clone will contain the property values from the
DbPropertyValues object used to create it. For example:
using (var context = new UnicornsContext())
{
var unicorn = context.Unicorns.Find(1);
var clonedUnicorn = context.Entry(unicorn).GetDatabaseValues().ToObject();
}
Note that the object returned is not the entity and is not being
tracked by the context. The returned object also does not have any
relationships set to other objects.
The cloned object can be useful for resolving issues related to
concurrent updates to the database, especially where a UI that
involves data binding to objects of a certain type is being used. (See
Part 9 for more details on dealing with optimistic concurrency.)
*From http://blogs.msdn.com/b/adonet/archive/2011/01/30/using-dbcontext-in-ef-feature-ctp5-part-5-working-with-property-values.aspx
Hope it can helps others
All troubles are gone once you're using EF 5+ where they introduced AsNoTracking() method.
The line below returns an unlinked instance, so all the context won't be aware about any changes in that instance:
context.Clients.AsNoTracking().FirstOrDefault(item => item.Id == id);
If Clients has a reference to Address and you want an unlinked instance of it too, just use an Include:
context.Clients
.Include("Address").AsNoTracking()
.FirstOrDefault(item => item.Id == id);
If it is a test you can do anything and you don't have to be binded to any architectural approach like repository. Your repository probably receive context as injection so you can have access to it. Another point is that I don't believe that AutoMapper will create tracked entity.
The one way to make a copy of the class is using serialization which by default saves only public fields (Xml serialization or DataContract serialization). Serialize the object and deserialize it back to a new instance. Serialization will save the whole object graph and deserialized object graph will be detached. Just be aware that that those serializations don't likes cyclic references in object graph (navigation property from A to B and from B to A from cycles). Serialization is also too much aggresive so it can traverse the graph more deeply then you want - this can be especially dangerous in many to many relations.
The best approach is using either ICloneable interface and implement Clone or define support methods which will do different clones with required depth.
Here is another approach for clonning EntityObject based entities. It is tough code, especially part with Reflection.Emit. But this will not help you because code-first is using POCOs.
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.