LinqToSql Cannot attach an entity "key is already in use"

LinqToSql Cannot attach an entity "key is already in use"

Old forum URL: forums.lhotka.net/forums/t/6084.aspx


tchimev posted on Tuesday, January 06, 2009

I have a Linq2Sql DataContext which I re-use in my business objects using CSLA's ContextManager class.

First I call DataPortal_Fetch to get an entity from the DataContext.
Then I transfer values from entity into my business base object's properties.

When I call Save() on the business base object it must be serialized/deserialized so I cannot keep pointer to the Linq2Sql entity.
I have to generate a new linq2sql entity from the business base object's properties and Attach it to the same DataContext during Save(),
I get an error: "Cannot attach an entity with a key that is already in use."

Is there a workaround for this error?


static void Main()
{
         using (var db = ContextManager<DB.DefaultDataContext>.GetManager(
                                                   Properties.Settings.Default.DefaultConnectionString, false))
        {
              BO.User user = BO.User.GetUser(17);
              user.Name += "A";
              user = user.Save();
        }
}

    [Serializable()]
    public class User : BusinessBase<User>
    {
        private static PropertyInfo<int> _id =
                                             RegisterProperty<int>(new PropertyInfo<int>("ID"));       
        public int ID
        { get { return GetProperty<int>(_id); } }

        private static PropertyInfo<string> _name =
                                             RegisterProperty<string>(new PropertyInfo<string>("Name"));
        public string Name
        {
            get { return GetProperty<string>(_name); }
            set { SetProperty<string>(_name, value); }
        }

        private byte[] _timeStamp = new byteMusic [8];

        public static User GetUser(int id)
        {
            return DataPortal.Fetch<User>(new Criteria() { IdField = id });
        }

        private User() {}

        [Serializable()]
        private class Criteria { public int IdField = 0; }

        protected override void DataPortal_Fetch(object criteria)
        {    
            using (var db = ContextManager<DB.DefaultDataContext>.GetManager(
                                                    Properties.Settings.Default.DefaultConnectionString, false))
            {
                DB.User dbUser = (from us in db.DataContext.Users
                                              where us.ID == ((Criteria)criteria).IdField
                                               select us).SingleOrDefault();

                LoadProperty<int>(_id, dbUser.ID);
                LoadProperty<string>(_name, dbUser.Name);
                this._timeStamp = dbUser.TimeStamp.ToArray();
            }
        }

        protected override void DataPortal_Update()
        {
            using (var db = ContextManager<DB.DefaultDataContext>.GetManager(
                                                    Properties.Settings.Default.DefaultConnectionString, false))
            {
                DB.User dbUser = new DB.User()
                {
                    ID = ReadProperty<int>(_id),
                    Name = ReadProperty<string>(_name),
                    Barcode = "",
                    TimeStamp = this._timeStamp
                };

                db.DataContext.Users.Attach(dbUser, this.IsSelfDirty);
                db.DataContext.SubmitChanges();

                this._timeStamp = dbUser.TimeStamp.ToArray();
            }
        }
    }


ajj3085 replied on Tuesday, January 06, 2009

You shouldn't need to use the ConnectionManager in your main method.  the BO should be hiding all data access from the client.  Remove that code and it should work.

tchimev replied on Tuesday, January 06, 2009

Thank you for your answer but this Main() is for testing only.

My point is that when you re-use the DataContext, sometime the fetched linq2sql entity stays in the context.
When I map the data from the BO to a new linq2sql entity and attach it, I get that error.

ajj3085 replied on Tuesday, January 06, 2009

Right, but your test is wrong.  You shouldn't be using ContextManager outside of any of the BO's DataPortal_XYZ methods.  The DataContext should go out of scope as soon as your BO's DataPortal_XYZ method exits.  That reduces the possiblity of the error you're getting, but doesn't eliminate it.  If you're still having the problem, your code is going to have to be smart enough to know whether or not the entity is already attached, and not re-attach it.

tchimev replied on Wednesday, January 07, 2009

Yes, that is what I'm trying to do.

How do I know if the entity is attached or not?
Does anyone have the same problem?

Copyright (c) Marimer LLC