This is a migrated thread and some comments may be shown as answers.

Instance of 'class' with identity 'guid' already exists in the cache of the object scope.

12 Answers 579 Views
Development (API, general questions)
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Urs
Top achievements
Rank 2
Urs asked on 10 Mar 2009, 11:14 AM
Hello OR-Mappers

I have an instance with a constant Guid as ID!

If I add it to the scope, then remove it and add it again, I get the error 'Instance of 'class' with identity 'guid' already exists in the cache of the object scope.'

It looks like:

OAObjectScope.Add(instance1)
... some Code
OAObjectScope.Remove(instance1)
... some Code
OAObjectScope.Add(instance2)

I know it's a bit strange, but users sometimes do not know what they want.

Adding Evict(instance) does not help.

Is this by design or is it a bug?

Thanks in advance.
Urs Scherrer

 

 

12 Answers, 1 is accepted

Sort by
0
tmlipinski
Top achievements
Rank 1
answered on 10 Mar 2009, 01:29 PM
Hi,

"Remove" just marks the removed object as "to be deleted from the database". The nearest Commit will delete it from the database (if it is an existing object) or do nothing (if it is a new one). Anyway - it doesn't remove the object from the scope's object collection. Therefore you get this error message. ("Evict" also works at the end of transaction - therefore it also doesn't help you).
The bad news is that it seems to be no way to remove an object from the scope - except executing Rollback. But it should be confirmed by somebody from the Telerik team.

Regards
Tomasz
0
Zoran
Telerik team
answered on 12 Mar 2009, 04:36 PM
Hello Urs,

The behavior you reported is a normal one because it seems that you do all the operations within a single transaction. It is matter of OpenAccess state handling e.g. when calling scope.Add(object1) and then scope.Remove(object1), object1 is marked with a state "NewRemoved" and is associated with the scope until Transaction.Commit() or Transaction.Rollback().

To be able to use the same Id to different objects you need to comit a transaction where the old one is deleted and the add an new instance with the id of the previously deleted object.

Greetings,
Zoran
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
0
Robert
Top achievements
Rank 1
answered on 21 Sep 2011, 01:44 PM
I know this is an older thread, but I am wondering if we are now able to add / remove items to a scope without persisting to the database.  Here is my use pattern:

1. User loads up a wizard with a bunch of info, information is pulled into scope from the database.
2. The user adds / removes (sometimes adds and removes) particular information
3. At the end of the wizard everything is persisted back to the database.

My problem is when the user is manipulating the data in step 2, sometimes they add a new item, then delete it, then re-add it and I am getting the error indicted in this thread.  Is there a way to delete a "NewRemoved" item completely from the object scope?  Or possibly change an already "NewRemoved" cached object to a "New" state so it will get persisted to the database when SaveChanges is called?

Is there a recommended way that I should handle this use that I am missing?

Thank you,
Robert Everett
0
Zoran
Telerik team
answered on 23 Sep 2011, 04:29 PM
Hi Robert,

 Unfortunately there is still no way to read/write an instance that was marked for removal. The only behavior that is changed with the latest versions is that there is no exception as the one stated in this thread when you try to re-add the object instance into the scope - just no change will be propagated to the database when you commit your transaction. You can only handle this scenario with your business logic at the moment, maybe you can use proxy objects before data is ready to be committed to the database. 

Greetings,
Zoran
the Telerik team

Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's SQL Server Community Awards. We are competing in TWO categories and every vote counts! VOTE for Telerik NOW >>

0
Robert
Top achievements
Rank 1
answered on 23 Sep 2011, 05:37 PM
Zoran,

Thanks for the reply.  I thought I may have to do something along these lines.  If that's the case then I would have to do the following:

  1. Load all items returned from the database into a "Business Object" collection.
  2. Whenever I add to my "Business Object" collection I would have to maintain a separate list of "New" object.
  3. Whenever I delete from my "Business Object" collection and the object I would have to remove it from the "New" objects collection (if it exists) and add it to a "ToDelete" collection.
  4. When I save I would then add what remains in the "New" Collection to the OpenAccess scope and delete any objects in the "ToDelete" collection from the OpenAccess scope.
  5. Save the OpenAccess scope

Since I'm new to OpenAccess, I thought this was more work than I would need to do.  Is there a better pattern that I should be using?

Thanks for your help!

Robert Everett
0
Zoran
Telerik team
answered on 28 Sep 2011, 02:01 PM
Hi Robert,

 Yes that is an approach that you can take. If the business logic of your application allows a the user to persist/delete multiple objects in one logical step than this is probably the best solution you can have. There is no best-practice approach for this scenario which I could recommend but your approach is very similar to the one that we have used in our ObjectProvider - that is the datasource component for windows forms that we are providing with our product.

Greetings,
Zoran
the Telerik team

Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's SQL Server Community Awards. We are competing in TWO categories and every vote counts! VOTE for Telerik NOW >>

0
Stargazer
Top achievements
Rank 1
answered on 16 Aug 2013, 04:19 PM
Hi!

I'm digging up this thread because I'm bumping into an issue similar to this, but can't seem to pinpoint the bugger.

So, I have a 3 layer system (GUI, BLL, DAL) and a data objects layer known by all the other three (BOBJ). I'm starting to use Open Access in a new subsystem and for the purpose of everyone of my colleagues work without (almost) any learning curve, I've implemented Open Access with same layered philosophy.

I made use of the Repository and Unit Of Work Patterns, as per several examples from Telerik and had those repositories in my DAL.
Then my "service" classes reside in the BLL and finally there are my web pages consuming the service classes. Taking advantage of the already existing BOBJ layer, I put the model in there also, so I'm using the Open Access Entities directly as my BOBJ classes. All works great for adding, loading and removing of entities. Only problem now is that when I load an entity (complex, with other objects and lists) it loads fine but if I save it, I got the exception:

"Instance of 'QS.PAAE.Pedagogico.BOBJ.ObjPessoa' with identity '239944776-1234567' already exists in the cache of the object scope."

The service (BLL) code is as follows:
// Check if there is an object in the repository, if so do not add a new one
if (!Exists(p => p.DocumentoID.Equals(busObj.DocumentoID)))
    mRepositorioPessoas.Add(busObj);
 
mUnitOfWork.SaveChanges();

Than in the DAL the repository looks like this:
public class PessoasRepository : Repository<ObjPessoa>
{
    public PessoasRepository(IUnitOfWork context) : base(context)
    {
         
    }
}

Which is an implementation of the abstract:
public abstract class Repository<T> : IRepository<T>
{
    protected Repository(IUnitOfWork context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context", "The given parameter cannot be null.");
        }
        this.Context = context;
    }
 
    protected IUnitOfWork Context
    {
        get;
        private set;
    }
 
    public virtual IList<T> GetAll()
    {
        return this.Context.GetAll<T>().ToList();
    }
 
    public virtual int CountAll()
    {
        return this.Context.GetAll<T>().Count();
    }
 
    public virtual IList<T> FindAll(Expression<Func<T, bool>> predicate)
    {
        return this.Context.GetAll<T>().Where(predicate).ToList();
    }
 
    public virtual void Add(T entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity", "The given parameter cannot be null.");
        }
 
        this.Context.Add(entity);
    }
 
    public virtual void Remove(T entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity", "The given parameter cannot be null.");
        }
 
        this.Context.Delete(entity);
    }
 
    public virtual void Dispose()
    {
        this.Context = null;
    }
}

I'm using .NET Framework 3.5 and OpenAccess 2013.2.702.1.

ANy one has some insight on the why this happens? Thanks!
0
Ady
Telerik team
answered on 20 Aug 2013, 04:33 PM
Hello Nuno,

 This error indicates that you are adding an object twice in the repository; it already exists when you try to add it a second time. Can you place a breakpoint in the 'Add' method of the repository class and debug to see if that is the case?

Regards,
Ady
Telerik
OpenAccess ORM Q2 2013 brings you a more powerful code generation and a unique Bulk Operations support with LINQ syntax. Check out the list of new functionality and improvements shipped with this release.
0
Stargazer
Top achievements
Rank 1
answered on 02 Sep 2013, 08:53 AM
Hello Ady,

Sorry for the (very) delayed reply, I've been in vacation.

Well, in fact, I'm not adding the object twice. I have a condition to prevent just that. My "service" code has a save method (my original post showed the code) that is responsible for saving the object changes, after checking if it exists or not in the repository:

public void Save(ObjPessoa busObj)
{
    // verifica se pode inserir
    if (!Exists(p => p.DocumentoID.Equals(busObj.DocumentoID)))
        mRepositorioPessoas.Add(busObj);
 
    mUnitOfWork.SaveChanges();
}

The suggested break-point is never hit. What is happening is that I load the entity, make some changes on it, and call the above save method. The code goes straight to the "mUnitOfWork.SaveChanges();" line.

Which calls the SaveChanges method of the OpenAccess context (OpenAccessContextBase), per the IUnitOfWork implementation suggested in the docs.

So, I'm lost. :)
0
Wolfgang
Top achievements
Rank 1
answered on 03 Sep 2013, 09:45 AM
Hi,

just have a similiar problem.

We copy somtimes objects between different machines.

Therefore we look wether an object is already existing in target scope before creating the object.

if(!targetContext.GetObjectById(objectScope.GetObjectId(sourceObject)))

Right now i encountered for some objects, that a message on commit appears, that a duplicate ID exists.

After 2 days of debugging i still do not see that the given object is created twice. But still the error occurs. This are the moments where i think it was easier without an ORM...

We also have the primary key of the object as property. the setter for the property is never called twice with same ID...

Is there any way to say: Regardless just put the last changes in DB?
0
Stargazer
Top achievements
Rank 2
answered on 03 Sep 2013, 12:19 PM
Hello all!

Well, I found the cause and solution to my problem. In fact it has nothing to do with OpenAccess but with the way I was using it. In my (web) application, there is a moment when I load my object graph. Then I show the data on my form.

After that, there's a SAVE button. When It is pressed, the form data get's passed to my object graph. The issue was that all the objects of the graph except the root one was getting a new instance in that moment, so open access assumed that they were new and tried to add them to the context...duh! :)

The solution was simply review that code and if there is nothing new, just use the instances already in loaded in the graph.
0
Ady
Telerik team
answered on 04 Sep 2013, 03:57 PM
Hi Nuno,

  I am glad that you found the solution to your problem. Do not hesitate to get back to us in case you need further assistance.

@Wolfgang - Can you open a ticket with details of your problem so that we can try and resolve it?

Regards,
Ady
Telerik
OpenAccess ORM Q2 2013 brings you a more powerful code generation and a unique Bulk Operations support with LINQ syntax. Check out the list of new functionality and improvements shipped with this release.
Tags
Development (API, general questions)
Asked by
Urs
Top achievements
Rank 2
Answers by
tmlipinski
Top achievements
Rank 1
Zoran
Telerik team
Robert
Top achievements
Rank 1
Stargazer
Top achievements
Rank 1
Ady
Telerik team
Wolfgang
Top achievements
Rank 1
Stargazer
Top achievements
Rank 2
Share this question
or