In ADO.Net Data Services how do I check if an entity is already in the context? - entity-framework

I have an ADO.Net Data Service that I am using to do a data import. There are a number of entities that are linked to by most entities. To do that during import I create those entities first, save them and then use .SetLink(EntityImport, "NavigationProperty", CreatedEntity). Now the first issue that I ran into was that the context did not always know about CreatedEntity (this is due to each of the entities being imported independently and a creation of a context as each item is created - I'd like to retain this functionality - i.e. I'm trying to avoid "just use one context" as the answer).
So I have a .AddToCreatedEntityType(CreatedEntity) before attempting to call SetLink. This of course works for the first time, but on the second pass I get the error message "the context is already tracking the entity".
Is there a way to check if the context is already tracking the entity (context.Contains(CreatedEntity) isn't yet implemented)? I was thinking about attempting a try catch and just avoiding the error, but that seems to create a new CreatedEntity each pass. It is looking like I need to use a LINQ to Data Services to get that CreatedEntity each time, but that seems innefficient - any suggestions?

I think you should look at the EntityState property of your entity.
Only if it is of the value EntityState.Detached than you have to add it to your context.
Do not forget the following remark:
This enumeration has a FlagsAttribute
attribute that allows a bitwise
combination of its member values.
I would create a extension method:
public static class EntityObjectExtensions
{
public static Boolean IsTracked(this EntityObject self)
{
return (self.EntityState & EntityState.Detached) != EntityState.Detached;
}
}

When trying to check whether the context was tracking the entity that I wanted to update (or add) I was pretty disapointed when I found that the context.Entites.Contains(currentItem) didn't work.
I got around it using:
if (context.Entities.Where(entities => entities.Entity == currentItem).Any())
{
this.service.UpdateObject(currentItem);
}

Related

Entity Framework 4 update

I have written a update method, given below:
public CANDIDATE UpdateCandidateDetails(CANDIDATE objCandidate)
{
using (var context = new URMSNEWEntities())
{
context.CANDIDATES.Attach(objCandidate);
context.ObjectStateManager.ChangeObjectState(objCandidate, System.Data.EntityState.Modified);
context.SaveChanges();
return objCandidate;
}
}
But when updating it is giving following error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
As Gert mentions in the comments that error is telling you that your object objCandidate, is already being tracked by another context.
You can't attach an already attached object, nor should you want to, as the two contexts are more than likely going to be in conflicting states.
In theory, you could Detach your object from the context to which it currently belongs, but that's likely to cause additional complications.
To track down where the object is attached (and the context to which it is attached), you'll have to look through your code to the place where your objCandidate was created (or attached), there will be another context that has been instantiated, from which you're obtaining the objCandidate object.
The best solution to the problem will likely involve sharing a common context throughout certain parts of your application.
Search this site for the UnitOfWork and Repository patterns for some excellent information/advice about how to manage your contexts. e.g. entity framework + repository + unit or work question
Good luck.

Saving single objects with Entity Framework code first

I am using Entity Framework 4.3.1 in a project, using code first and the DbContext API. My app is an n-tier app where disconnected objects may come in from a client. I am using SQL Server 2008 R2 but will be moving to SQL Azure soon. I am running into an issue I just can't seem to solve.
Imagine I have a few classes:
class A {
// Random stuff here
}
class B {
// Random stuff here
public A MyA { get; set; }
}
class C {
// Random stuff here
public A MyA { get; set; }
}
By default, EF operates on object graphs. For instance, if I have an instance of B that encapsulates an instance of A and I call myDbSet.Add(myB);, it will also mark the instance of A as being added (assuming it is not yet being tracked).
I have a scenario in my app where I need to be explicit about which objects get persisted to the database, rather than have it track entire object graphs. The order of operations is as follows:
A myA = new A(); // Represents something already in DB that doesn't need to be udpated.
C myC = new C() { // Represents something already in DB that DOES need to be updated.
A = myA;
}
B myB0 = new B() { // Not yet in DB.
A = myA;
}
B myB1 = new B() { // Not yet in DB.
A = myA;
}
myDbSetC.Attach(myC);
context.Entry(myC).State = Modified;
myDbSetB.Add(myB0); // Tries to track myA with a state of Added
myDbSetB.Add(myB1);
context.SaveChanges();
At this point I get an error saying AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges. I believe this happens because calling add on myB0 marks the instance of A as being Added, which conflicts with the instance of A already being tracked.
Ideally I could do something like call myDbSet.AddOnly(myB), but obviously we don't have that option.
I have tried several workarounds:
Attempt #1:
First, I tried creating a helper method to prevent myA from being added a second time.
private void MarkGraphAsUnchanged<TEntity>(TEntity entity) where TEntity : class {
DbEntityEntry entryForThis = this.context.Entry<TEntity>(entity);
IEnumerable<DbEntityEntry> entriesItWantsToChange = this.context.ChangeTracker.Entries().Distinct();
foreach (DbEntityEntry entry in entriesItWantsToChange) {
if (!entryForThis.Equals(entry)) {
entry.State = System.Data.EntityState.Unchanged;
}
}
}
...
myDbSetB.Add(myB0);
MarkGraphAsUnchanged(myB0);
While this solves the problem of it trying to add myA, it still causes key violations within the ObjectStateManager.
Attempt #2:
I tried doing the same as above, but setting the state to Detached instead of Unchanged. This works for saving, but it insists on setting myB0.A = null, which has other adverse effects in my code.
Attempt #3:
I used a TransactionScope around my the entire DbContext. However, even when calling SaveChanges() between each Attach() and Add(), the change tracker does not flush its tracked entries so I have the same problem as in attempt #1.
Attempt #4:
I continued with the TransactionScope, except I used a repository/DAO pattern and internally create a new DbContext and call SaveChanges() for each distinct operation I do. In this case, I got an error 'Store update, insert, or delete statement affected an unexpected number of rows.' When using the SQL Profiler, I find that when calling SaveChanges() on the second operation I did (the first Add()), it actually sends the UPDATE SQL to the database from the first operation a second time -- but doesn't change any rows. This feels like a bug in Entity Framework to me.
Attempt #5:
Instead of using the TransactionScope, I decided to use use a DbTransaction only. I still create multiple contexts but pass a pre-built EntityConnection to each new context as it's created (by caching and manually opening the EntityConnection built by the first context). However, when I do this, the second context runs an initializer I have defined, even though it would have already run when the app first started up. In a dev environment I have this seeding some test data, and it actually times out wating for a database lock on a table my first Attach() modified (but is still locked due to the transaction still being open).
Help!! I've tried about everything I can think of, and short of completely refactoring my app to not use navigation properties or using manually constructed DAOs to do INSERT, UPDATE, and DELETE statements, I'm at a loss. It seems there must be a way to get the benefits of Entity Framework for O/R mapping but still manually controlling operations within a transaction!
There must be something else you are not showing because there is no problem with the way how you attach and add entities. The following code will attach myA, myC, myB0 and myB1 to context as unchanged and set state of myC to modified.
myDbSetC.Attach(myC);
context.Entry(myC).State = Modified;
the following code will correctly detect that all entities are already attached and instead of throwing exception (as it would do in ObjectContext API) or inserting all entities again (as you expect) it would just change myB0 and myB1 to added state:
myDbSetB.Add(myB0);
myDbSetB.Add(myB1);
If your myA and myC are correctly initialized with keys of existing entities whole code will correctly execute and save except the single problem:
C myC = new C() {
A = myA;
}
This looks like independent association and independent association has its own state but API to set its state is not available in DbContext API. If this is a new relation you want to save it will not be saved because it is still tracked as unchanged. You must either use foreign key association or you must convert your context to ObjectContext:
ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
and use ObjectStateManager to change state of the relation.
As Ladislav suggested, I got the object instances consistent, which solved the problem of it trying to add redundant As.
As it turns out, both B0 and B1 actually encapsulate other objects (D0 and D1, respectively) which in turn encapsulate A. Both D0 and D1 were already in the database but not being tracked by Entity.
Adding B0/B1 caused D0/D1 to also be inserted, erroneously. I ended up using the object context API Ladislav suggested to both mark the ObjectStateEntry for D0/D1 to Unchanged, and the relationships between D0/D1 and A as Unchanged. This seems to do what I need: update C and insert B0/B1 only.
Below is my code to do this, which I call right before SaveChanges. Note that I'm sure there are still some edge cases that are not handled, and this is not throughly tested -- but it should give a rough idea what needs to be done.
// Entries are put in here when they are explicitly added, modified, or deleted.
private ISet<DbEntityEntry> trackedEntries = new HashSet<DbEntityEntry>();
private void MarkGraphAsUnchanged()
{
IEnumerable<DbEntityEntry> entriesItWantsToChange = this.context.ChangeTracker.Entries().Distinct();
foreach (DbEntityEntry entry in entriesItWantsToChange)
{
if (!this.trackedEntries.Contains(entry))
{
entry.State = System.Data.EntityState.Unchanged;
}
}
IEnumerable<ObjectStateEntry> allEntries =
this.context.ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added)
.Union(this.context.ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted))
.Union(this.context.ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified));
foreach (ObjectStateEntry entry in allEntries)
{
if (entry.IsRelationship)
{
/* We can't mark relationships are being unchanged if we are truly adding or deleting the entity.
* To determine this, we need to first lookup the entity keys, then state entries themselves.
*/
EntityKey key1 = null;
EntityKey key2 = null;
if (entry.State == EntityState.Deleted)
{
key1 = (EntityKey)entry.OriginalValues[0];
key2 = (EntityKey)entry.OriginalValues[1];
}
else if (entry.State == EntityState.Added)
{
key1 = (EntityKey)entry.CurrentValues[0];
key2 = (EntityKey)entry.CurrentValues[1];
}
ObjectStateEntry entry1 = this.context.ObjectContext.ObjectStateManager.GetObjectStateEntry(key1);
ObjectStateEntry entry2 = this.context.ObjectContext.ObjectStateManager.GetObjectStateEntry(key2);
if ((entry1.State != EntityState.Added) && (entry1.State != EntityState.Deleted) && (entry2.State != EntityState.Added) && (entry2.State != EntityState.Deleted))
{
entry.ChangeState(EntityState.Unchanged);
}
}
}
}
Whew!!! The basic pattern is:
Explicitly track changes as they are made.
Go back and clean up all the things Entity thinks it needs to do, but doesn't really.
Actually save the changes out to the DB.
This having to "go back and clean up" method is obviously sub-optimal, but it seems to be the best option for the moment, without having to manually attach peripheral entities (such as D0/D1) before I attempt any save operation. Having all this logic in a generic repository helps -- the logic only needs to be written once. I do hope in a future release, Entity can add this capability directly (and remove the restriction about having multiple instances of an object on the heap but with the same key).

Force Entity Framework to return a new instance

We have a scenario in our code when only a few properties of an entity are allowed to be changed. To guarantee that, we have code similar to this:
public void SaveCustomer(Customer customer)
{
var originalCustomer = dbContext.GetCustomerById(customer.Id);
if (customer.Name != originalCustomer.Name)
{
throw new Exception("Customer name may not be changed.");
}
originalCustomer.Address = customer.Address;
originalCustomer.City = customer.City;
dbContext.SaveChanges();
}
The problem with this code is that the call to dbContext.GetCustomerById does not always gives me a new instance of the Customer class. If the customer already has been fetched from the database, Entity Framework will keep the instance in memory and return it on every subsequent call.
This leads us to the actual problem - customer and originalCustomer may refer to the same instance. In that case, customer.Name will be equal to originalCustomer.Name and we will not be able to detect if it differs from the database.
I guess the same problem exists with most other ORMs as well, because of the identitymap design pattern.
Any ideas how this can be solved? Can I somehow force EF to always give me a new instance of the customer class?
Or should we refactor the code instead? Does anyone know of any good design patterns for this scenario?
you can try by detaching the entity from the context, this will remove all the references to the context (as well as the identitymap behaviour).
So, before passing the Customer to your method you can detach it:
yourContext.Detach(customer);

EF 4.0 IsAttachedTo extension method and error An object with the same key already exists

I was getting an error
An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same
key.
After i googled it i found IsAttachedTo extension method there:
Is is possible to check if an object is already attached to a data context in Entity Framework?
here is my code:
foreach (string s in types)
{
Subscription subscription = new Subscription { Id = Int32.Parse(s) };
if (service.repository._context.IsAttachedTo(subscription))
service.repository._context.Detach(subscription);
service.repository._context.AttachTo("Subscriptions", subscription); //error here
horse.Subscriptions.Add(subscription);
}
But when the subscription with the same key appeared in the foreach loop the extension method IsAttachedTo returning false every time, it is does not detect that there is already such entity attached. And in result i am getting the same error:
An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same
key.
Why it is could be?
What can i do to fix that?
I have little code review for you because your sample code scares me.
You probably read a lot about fancy design patterns and layered architectures and you started to use them yourselves. Unfortunately you missed the main point. What the hell is this?
service.repository._context.XXX
Why do you bother with any service layer or repository layer if they don't encapsulate their logic? Why do you expose repository on the service? Nobody should know about service internal implementation? Even worse why do you expose context on the repository? That spoiled the whole point of the repository!
There are a lot of supporting rules for writing high quality object oriented code. One of this rules is called Law of Demeter. You don't have to follow each rule, you also don't have to follow rules all the time but in case of layered architecture this law is a must.
If you have three layers A -> B -> C the layer A can call methods on the layer B but it doesn't know about C and it cannot reach its methods. If it can, it is not a new layer but it is the same layer as B and the layer A doesn't need to call it through B, it can call it directly.
In your example you have just exposed D to A because A is current layer, B is service, C is repository and D is context.
One more points about your code. There are well known naming conventions. These conventions are not about I like this and you like that but about the fact that framework you are using follow these conventions strictly so using another one to mix your naming convention with framework naming convention make your code look messy.
I'm sorry, If this was only some example code to make your code structuring clear. I just needed to describe how wrong this code is.
Now to your real problem. The method you have referenced from the related question will not work in your case. I think it will work only if you load the subscription from the database. The reason is that the referenced method uses EntityKey (either internally or directly) to get the entity from context but your new entity doesn't have the entity key yet. I expect that calling TryGetObjectStateEntry for your entity will always return Detached. Entity key it is created during attaching or you have to build it manually.
If you want some IsAttachedTo method try this:
public bool IsAttachedTo<T>(this ObjectContext context, T entity) where T : IEntity
{
return context.GetObjectStateEntries(~EntityState.Detached)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<T>()
.Any(e => e.Id == entity.Id);
}
And make sure that your entity implements helper interface
public interface IEntity
{
int Id { get; }
}
But to be able to detach attached entity you will need:
public T GetAttached<T>(this ObjectContext context, T entity) where T : IEntity
{
return context.GetObjectStateEntries(~EntityState.Detached)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<T>()
.SingleOrDefault(e => e.Id == entity.Id);
}
You will have to detach instance returned from this method.
Anyway I would start to think why do you need that for the first place because it looks like your architecture has another wrong concept. Why don't you use attached entities directly? If you don't use them why do you even keep the context with them?
It's likely that IsAttachedTo does not compare by the key (Id) but by object identity. Because you create a new Subscription for every item in the loop the objects are all different instances.
Since you seem to have objects with same Id in your types collection but in the end only want to add one object per key into the context you can perhaps make your life easier by filtering out the duplicates in the first place:
var distinctTypes = types.Distinct();
foreach (string s in distinctTypes)
{
Subscription subscription = new Subscription { Id = Int32.Parse(s) };
service.repository._context.AttachTo("Subscriptions", subscription);
horse.Subscriptions.Add(subscription);
}
This way there should be only one object per key which gets attached to the context.

Entity Framework v4 POCO templates: repository returns object of incorrect type

I've just implemented a repository based on EFv4 POCO entity templates.
When I do this
public Client Load(Guid firmId,
int prettyId)
{
var client = (from c in _ctx.Clients where c.firm_id == firmId && c.PrettyId == prettyId select c).FirstOrDefault();
return client;
}
the client returned is of type
{System.Data.Entity.DynamicProxies.Client_8E92CA62619EB03F03DF1A1FC60C5B21F87ECC5D85B65759DB3A3949B8A606D3}
What is happening here? I thought I would get rid of any reference to types from System.Data.Entity namespace. The returned instance should be of type Client, which is a simple POCO class.
I can confirm that the solution is to set
context.ProxyCreationEnabled = false;
which disables creation of dynamic proxy typed objects and leaves us with simple POCOs, which is what we were after with EF POCO templates in the first place.
But you lose lazy loading of navigation properties and change tracking on entities. For the first, you either have to use context.LoadProperty() or the Include() method on your ObjectQuery object. For the second, I do not know the solution yet (actually it doesn't really make sense to have change tracking on POCOs).
Also here is a similar question I would like to point out
What are the downsides to turning off ProxyCreationEnabled for CTP5 of EF code first
I agree that Mare's answer is correct. However, I would add a note of caution.
If you run a query without this ProxyCreationEnabled setting set to true, then EF will return DynamicProxies. If you subsequently run a query with the setting set to false, then EF will return the cached DynamicProxies objects, regardless of the ProxyCreationEnabled setting.
This can be configured globally for the EF context in the *Model.Context.tt file in *Model.edmx under
if (!loader.IsLazyLoadingEnabled(container))
...
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
These will be added to the *Model.context.cs generated file, and will persist between updates from the Database.
I prefer this setting as I do not want a child object that matches the parent loaded from the database.
ALT: It can be configured for Json serizialization:
JSON.NET Error Self referencing loop detected for type