Collin O'Connor
Collin O'Connor

Reputation: 1351

Cannot attach an entity that already exists

I get this error whenever i try to update one of my models. The update is pretty simple:

Todo bn = service.GetTodos().Single(t => t.todoId == 1);
bn.Note.noteTitle = "Something new";
service.SaveTodo(bn);

And the models have this kind of structure:

I have my service's SaveTodo look a little something like this:

public void SaveTodo ( TodoWrapper note )
{
    using (Repository repo = new Repository(new HpstrDataContext()))
    {
        if (note != null)
        {
            Todo todo = repo.Todos.SingleOrDefault(t => t.todoId == note.todoId);
            if (todo == null)
            {
                todo = new Todo();
                todo.Note = new Note();
            }
            todo.dueDate = note.dueDate;
            todo.priority = (short)note.priority;

            todo.Note.isTrashed = note.Note.isTrashed;
            todo.Note.permission = (short)note.Note.permission;
            todo.Note.noteTitle = note.Note.noteTitle;

            repo.SaveTodo(todo);
        }
    }
}

And the Repository's SaveTodo method is pretty simple and looks like this:

public void SaveTodo ( Todo todo )
{
    if (todo.Note.noteId == 0)
    {
        dc.NoteTable.InsertOnSubmit(todo.Note);
    } else
    {
        dc.NoteTable.Attach(todo.Note);
        dc.NoteTable.Context.Refresh(RefreshMode.KeepCurrentValues , todo.Note);
    }
    if (todo.todoId == 0)
    {
        dc.TodoTable.InsertOnSubmit(todo);
    } else
    {
        dc.TodoTable.Attach(todo);
        dc.TodoTable.Context.Refresh(RefreshMode.KeepCurrentValues , todo);
    }
    dc.SubmitChanges();
}

The error is being thrown at this line in the Repository: dc.NoteTable.Attach(todo.Note);. I've tried a lot of different things to get this to work but nothing seems to work.

Any help would be greatly appreciated

Upvotes: 3

Views: 2107

Answers (1)

Collin O'Connor
Collin O'Connor

Reputation: 1351

So i solved the problem (hopefully). In my Repository, i changed the SaveTodo to look like this

public void SaveTodo ( TodoWrapper note )
{
    using (Repository repo = new Repository(new HpstrDataContext()))
    {
        if (note != null)
        {
            Todo todo = repo.Todos.SingleOrDefault(t => t.todoId == note.todoId);
            if (todo == null)
            {
                todo = new Todo();
                todo.Note = new Note();
            }
            todo.dueDate = note.dueDate;
            todo.priority = (short)note.priority;
            todo.Note.isTrashed = note.Note.isTrashed;
            todo.Note.permission = (short)note.Note.permission;
            todo.Note.noteTitle = note.Note.noteTitle;
            foreach (TaskWrapper item in note.Tasks)
            {
                Task t = repo.Tasks.SingleOrDefault(task => task.tasksId == item.taskId);
                if (t == null)
                {
                    t = new Task();
                }
                t.Todo = todo;
                t.isCompleted = item.isCompleted;
                t.content = item.content;
                repo.SaveTask(t);
            }
        }
    }
}

If anybody was wondering, the wrappers are used as wrappers (no way) for the entities with wcf.

And my save task looked like this:

public void SaveTask ( Task task )
{
    if (task.tasksId == 0)
    {
        dc.TaskTable.InsertOnSubmit(task);
    } else
    {
        dc.TaskTable.Context.Refresh(RefreshMode.KeepCurrentValues , task);
    }
    dc.SubmitChanges();
}

I got rid of the Attach because I already pull out the Todo when calling the single or default statement so it was already attached to the database. So the error was correct because this entity was already attached to the database. If i had made a new Todo instead of grabbing the one out the database, the attach would have worked. Hope this helps out anyone who stumbles upon this

Upvotes: 2

Related Questions