I am having a problem inserting and removing objects to/from the database using Linq to SQL when utilitizing different Data contexts. The code works just fine as long as I insert and remove using the same context. However using the same context for each function is not an option as this will introduce concurrency problems as the code is used for a web service.
The code is written in F#, but it shouldn’t do any difference.
let CreateUser user =
use context = new Rsvp(connectionString)
context.Users.InsertOnSubmit(user)
context.SubmitChanges()
let RemoveUserById user_id =
use context = new Rsvp(connectionString)
let user = GetUser user_id
context.Users.DeleteOnSubmit(user)
context.SubmitChanges()
An exeception is thrown from DeleteOnSubmit as follows:
System.InvalidOperationException: Cannot remove an entity that has not been attached.
Now you would think that you could just attach the object to the new data context. However doing so will cause another exception:
System.NotSupportedException: An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported.
I am testing this from a C# test project with the following method
[TestMethod]
public void Can_create_and_remove_a_new_user()
{
User user = new User();
user.Name = "Test User";
user.Email = "test@mail.com";
user.Role_id = 1;
UserModule.CreateUser(user);
User inserted_user = UserModule.GetUserByEmail("test@mail.com");
Assert.IsNotNull(inserted_user);
UserModule.RemoveUserById(inserted_user.Id);
}
Isn’t it possible to remove/insert the same object from different contexts?
EDIT:
A friend send me this article that could help to solve the problem but it doesn’t seem to be a definitive solution to the problem.
I think that’s just how
DataContextworks. An entity can belong only to a single data context and when you need to work with it for some time, you should keep the data context you used to retreive the entity.If you wanted to play with some nice functional ideas, this may be a good place to implement computation builder to keep the data context around (i.e. state monad). Then you could write:
Where
getCurrentContextis an operation that returns the context that you’re passing around. There are probably a few examples how to implement state monad in F#. See for example this article.