English 中文(简体)
C# CodeSmith LINQ to SQL question DELETE Operation
原标题:

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.

最佳回答

This is an old question however we were never able to make this delete to both tables simultaneously. Our solution was to delete from one then the other and commit the changes in between.

问题回答

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)





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Transaction handling with TransactionScope

I am implementing Transaction using TransactionScope with the help this MSDN article http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx I just want to confirm that is ...

System.Web.Mvc.Controller Initialize

i have the following base controller... public class BaseController : Controller { protected override void Initialize(System.Web.Routing.RequestContext requestContext) { if (...

Microsoft.Contracts namespace

For what it is necessary Microsoft.Contracts namespace in asp.net? I mean, in what cases I could write using Microsoft.Contracts;?

Separator line in ASP.NET

I d like to add a simple separator line in an aspx web form. Does anyone know how? It sounds easy enough, but still I can t manage to find how to do it.. 10x!

热门标签