views:

55

answers:

1

In a project I am working on I need to delete a "user" from my database. This "user" has two tables that reference it's foreign key. When hard deleting I am trying to delete all records from Table A and Table B that have foreign keys to the "user" and then deleting that "user" record. This is all done within repositories and using object factory.

The code is as follows:

public void RemoveUserByUserId(int userId)
{
var user = m_context.User.GetByKey(userId);

ObjectFactory.Inject(m_context);

UserTokenRepository.RemoveUserTokensByUserId(userId);
UserMappingRepository.RemoveUserMappingsByUserId(userId);

m_context.User.DeleteOnSubmit(user);

m_context.SubmitChanges();

ObjectFactory.ResetDefaults();
}

public static void RemoveUserTokensByUserId(int userId)
{
var dataContext = ObjectFactory.GetInstance<DataContext>();
var userTokens = dataContext.UserToken.ByUserId(userId);
dataContext.UserToken.DeleteAllOnSubmit(userTokens.AsEnumerable());
}

public static void RemoveUserMappingsByUserId(int userId)
{
var dataContext = ObjectFactory.GetInstance<DataContext>();
var userMappings= dataContext.UserMapping.ByUserId(userId);
dataContext.UserMapping.DeleteAllOnSubmit(userMappings.AsEnumerable());
}

If each table has one record, it works fine. If a table has multiple, which can only happen on the UserToken and UserMappings, I get the following error.

System.ArgumentException was unhandled by user code
Message=An item with the same key has already been added.
  Source=mscorlib
  StackTrace:
       at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
       at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
       at System.Data.Linq.ChangeProcessor.EdgeMap.Add(MetaAssociation assoc, TrackedObject from, TrackedObject to)
       at System.Data.Linq.ChangeProcessor.BuildEdgeMaps()
       at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
       at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
       at XXXX.XXXX.XXXX.XXXXDataContext.SubmitChanges(ConflictMode failureMode) in XXXX:line 519
       at System.Data.Linq.DataContext.SubmitChanges()
       at XXXX.UserRepository.RemoveUserByUserId(Int32 userId) in XXXX:line 146
       at XXXX(Int32 profileUserId) in XXXX:line 948
       at XXXX(Int32 profileUserId) in XXXX:line 165
       at SyncInvokeUnregisterUserForActivationFailed(Object , Object[] , Object[] )
       at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
       at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)

I had to put in XXXX for privacy reasons. What I read this as was that however LINQ is storing preping the changes for SQL it puts it into a Dictionary, and somehow the key for two things is the same and it errors before a change occurs.

Any help would be much appreciated.

A: 

I am kinda shooting in the dark here and assuming how you read it is correct along with a little pain i've had along the way.

do the tables you are deleting from have their own primary key or are you using the foreign key as the pk? (well you know what i mean ... it doesn't sound like they have their own independent unique primary key that linq is aware of)'

linq uses the GetHash method to construct a unique id from the primary key fields .. i am guessing that these fields duplicate and hence the dictionary problem ... the problem is not caused by 2 different tables having the same key id.

I am guessing that these tables with multiple items in are a kind of in the middle of a many to many join. A quick and dirty fix would be to add an auto increment column to them nd assign this to the primary key (otherwise try using a multi field pk - which i haven;t really tried out with linq deliberatley).

I hope this gives you some ideas ... you could override GetHashCode in a partial class to fix your problem another way ... however you should only include the parts of your data that are invariant accross a single item)

John Nicholas
Actually each table has a primary key. the structure is as follows. User table[pk: user_id] UserToken table - [pk: token_id (guid)] [fk: user_mapping_id] [fk: user_id] UserMapping table - [pk: user_mapping_id] [fk: user_id]
Zambouras