3
votes

When I try to add a new item to my EntitySet, I'm getting this exception:

An entity with the same identity already exists in this EntitySet

However, when I inspect the EntitySet its count is 0.

Any ideas why I would be getting this error when the set is empty? How could an entity already exist in the set if the set has no items in it?

UPDATE

I've narrowed this down a bit more. This is only happening if I add the item to the set, remove it, then re-add it. Even tho the item isn't in the EntitySet any more it is still remembering it somehow. What do I need to do to make it forget?

UPDATE: Here are some code snippets for the classes and logic involved.

Server Entities:

public class PhotoDto
{
    [Key]
    [Editable(false)]
    public int Id { get; set; }

    /* clip */

    [Include]
    [Association("Photo_Destination", "Id", "PhotoId")]
    public EntitySet<PhotoDestinationDto> Destinations { get; set; }
}

public class PhotoDestinationDto : BaseDestionationDto
{
    [Key]
    [Editable(false, AllowInitialValue = true)]
    public int PhotoId { get; set; }

    [Key]
    [Editable(false, AllowInitialValue = true)]
    public bool IsAnnotated { get; set; }

    [Key]
    [Editable(false, AllowInitialValue = true)]
    public int DropZoneId { get; set; }
}

public class BaseDestinationDto
{
    [Key]
    [Editable(false, AllowInitialValue = true)]
    public Guid DatabaseUid { get; set; }

    [Key]
    [Editable(false, AllowInitialValue = true)]
    public string Unit { get; set; }

    [Key]
    [Editable(false, AllowInitialValue = true)]
    public string EqCircId { get; set; }

    [Key]
    [Editable(false, AllowInitialValue = true)]
    public string EqType { get; set; }
}

Client side GetIdentity() for PhotoDestinationDto:

/// <summary>
/// Computes a value from the key fields that uniquely identifies this entity instance.
/// </summary>
/// <returns>An object instance that uniquely identifies this entity instance.</returns>
public override object GetIdentity()
{
    if ((((this._eqCircId == null) 
                || (this._eqType == null)) 
                || (this._unit == null)))
    {
        return null;
    }
    return EntityKey.Create(this._dropZoneId, this._eqCircId, this._eqType, this._isAnnotated, this._photoId, this._unit, this._databaseUid);
}

To remove photo destination client side:

PhotoDto photo = GetPhotoDto();
PhotoDestinationDto destToRemove = photo.Destinations.First(x => x.DropZoneId == 1);
photo.Destinations.Remove(destToRemove);

To add photo destination client side:

var dest = new PhotoDestinationDto
{
    DropZoneId = zoneId,
    EqCircId = selectedEqCircId,
    EqType = selectedEqType,
    Unit = selectedUnit,
    PhotoId = id,
    DatabaseUid = selectedDatabaseId
};

p.Destinations.Add(dest); // this is where exception is thrown. p.Destinations.Count is 0 here.
6
A shot in the dark: is the entity set missing the KeyAttribute ?Timores
I have an [Association] attribute on the actual EntitySet<T> property. The T type that is in the EntitySet<> also has properties with [Key] attributes.joshuapoehls

6 Answers

6
votes

Juding by your code Unit = selectedUnit and p.Destinations.Add(dest); and the other symptoms you describe you seem to have the exact same situation. My findings below have fixed the problem for me.

Interested also if you ended up with any duplicated entities in your database as a result of this. i was getting rows already previously saved magically turning to New and then becoming dupe records. Again this simple change below fixed it.


There is a race condition i discovered that can give this error if you create an entity and immediately assign foreign key relationships to it before adding the parent entity to its entity set.

Turns out the very act of setting the foreign key relationship actually adds the entity to its corresponding entity set - but sometimes causes a race condition, especially if your UI is loading and saving and clearing entity sets.

bad:

var todo = new TODO();
todo.Status = TODOContext.Statuses.Single(x=>x.Status == "Unknown");
todo.AssignedTo = TODOContext.Users.Single(x=>x.UserName == "JSMITH");
TODOContext.TODOs.Add(todo); // adding entity after setting FK

good:

var todo = new TODO();
TODOContext.TODOs.Add(todo); // add entity before setting FK
todo.Status = TODOContext.Statuses.Single(x=>x.Status == "Unknown");
todo.AssignedTo = TODOContext.Users.Single(x=>x.UserName == "JSMITH");
3
votes

Ok, after seeing your code I see the issue. When removing from an EntityCollection the entity isn't actually removed (as in a pending delete) - the association is only severed, with FKs set to their default values. So your photo.Destinations.Remove() call doesn't actually remove the entity from the DomainContext (ctxt.PhotoDestinationDtos EntitySet). That's why you're getting the cache collision.

To actually remove it, you should be calling ctxt.PhotoDestinationDtos.Remove.

1
votes

I had the same issue, I later realised that there is a row in the database where the ID column was "0", everytime we try to save the new record it initially inserts it with 0 in the ID column, I deleted the one that is already present and my code was working perfectly fine, I did not change the Inser method created by the DomainService class,

1
votes

Anyone who is still getting this error, after trying above fixes I was still getting the error. Finally I am able to fix it by assigning a new Unique id to my Identity id even though this won't be updated in the database.

0
votes

Have you made sure you have a PK/identity properly defined in your db on that table, and it is reflected in your model? Try overriding OnError in your DomainService to get more info on the server-side exception. (You're getting this error on the client/Silverlight side, right?)

0
votes

When you remove an entity from an EntitySet, the associated record in the database should be deleted during SubmitChanges(). For this reason, the entity must continue to track the entity - even after it has been removed. It is required for the generation of the delete statement.

Although it is no longer available within the EntitySet directly (the Results View node in the image below), the entity is tracked within the private _IdentityCache property. In the example below, I have only a single entity within the EntitySet...

enter image description here

...however there are two items in the _identityCache property.

enter image description here

You can access the entities tracked by an EntitySet that have an EntityState of Deleted using the following code.

entitySet.EntityContainer.GetChanges().RemovedEntities

In your case, you should either reuse the existing entity in the RemovedEntities collection from above or detach it before adding a new one with the same key.