delete data using entity framework - asp.net-mvc

The objective of the method below is to delete the data from the database using entity framework. I am populating the subscriptions entity by passing two parameters and then calling the atttach and remove method of the context class. Bureau entities is the context class.
using (BUREAUEntities bureauEntities = new BUREAUEntities())
{
var subscription = new SubcriptionRepository().GetSusbcriptionBySubscriptionTypeId(subscriptionTypeId, companyId);
bureauEntities.Subscriptions.Attach((DataAccessLayer.DatabaseModel.Subscription)subscription);
bureauEntities.Subscriptions.Remove(subscription);
bureauEntities.SaveChanges();
}
I am getting the following error message at An entity object cannot be referenced by multiple instances of IEntityChangeTracker at line
bureauEntities.Subscriptions.Attach((DataAccessLayer.DatabaseModel.Subscription)subscription);
Could somebody tell me where am I going wrong ?

Generally, the error means that you retrieved subscription from one instance of your BUREAUEntities context, while you're trying to remove it from another instance. The cure is to simply be smart about instantiating your context, and it's easy to fall down on that front when using using, since it disposes of the instance as soon as the block exits.
Essentially, make sure all your code that will interact with your context is within the same using block. Even better, use a DI (dependency injection) container like Ninject or Unity to create a context scoped to the request. Then you never have to worry about ending up with multiple copies of the same context floating around.

Related

Cocoa Core Data - best practice to check if object with the same property already exists

I would like to check with you the best practice to solve the following task in Core Data framework. In my model one of the property for one object type must be unique. Let's say I have object Account - the property name must be unique - it is not allowed to have 2 accounts with same name.
There are 2 possibilities:
either I execute validation before I call insert into context -> at this point my new object is still not inserted into context, so I can call fetch from context and check if there is already account with particular name
or I overwrite built in validation methods and put my validation there as mentioned here:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdValidation.html#//apple_ref/doc/uid/TP40004807-SW1 - all these validation methods are called only after context is saved
I personally like second case, because my validation would be in model. But the problem is that at this point the object is already inserted into context and therefore if I call fetch, the validation always fails, because also the name of new object counts (even if is still not saved permanently). There is a solution for this however. I can check solely the permanent saved objects by creating new temporary managed object context and call fetch
Is this the best practice to execute such a validation. Or am I missing something or there is better way to do it ?
BR
Lubos
I would go about it in the following way. In general, it is advisable to avoid the complexities of multiple contexts, although that too is a pattern demoed by Apple.
Create the new managed object, insert it into the context. Check against existing names. If the name is not valid, prompt for a different name. Repeat until the name is valid. If the user breaks off the process or times out, delete the object.
If you can do that before saving, discarding the object could be as simple as calling [context rollback];.
If you do this in a separate controller, you could do it in a child context. If the user terminates the process, you just throw away the context altogether without saving.
If you find a name exists but suspect that it is the name being created you can easily check it it is the same object (you already have a reference to it). You could also do a fetch (or, more efficiently, countForFetchRequest) with a predicate that excludes this particular object.
NSPredicate(format:"name = %# && (not self = %#)", account.name, account)

Error when adding to many-to-many table in EF6

I have recently changed from ObjectContext to DbContext using EntityFramwework by upgrading to EF6
Most stuff works, but saving and updating won't. Here is an example:
public void AssignToAdmin(Product product, Admin admin)
{
var pcsps = from s in context.ProductCreationSections
join pcsp in context.ProductCreationSectionAndProducts on s.ProductCreationSecitionID equals pcsp.ProductCreationSectionID
where pcsp.ProductID == product.ProductID && s.IsManagerAssigned
select pcsp;
foreach (var pcsp in pcsps.Include("AssignedAdmins"))
{
pcsp.AssignedAdmins.Add(admin);
}
}
Trying to execute the line pcsp.AssignedAdmins.Add(admin), I get the error:
Error: The relationship between the two objects cannot be defined
because they are attached to different ObjectContext objects.
There is one context for the class and it comes from Dependency Injection (the class is a Service in an MVC app).
I've tried removing/attaching and so on, but this doesn't fix it - it just gives different error messages. It's not even obvious which entity is using another context.
Any ideas of where this other context the error message refers to is coming from?
See The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects
Where has admin come from?
Getting the admin object from the same context as the pcsp object should help.
Sorted it, but it was quite a major refactor.
The issue was that each service received it's own instance of 'context', so when two entities from two services were expected to work together, they wouldn't as each belonged to a different context.
One solution would have been to make the class that created the context a 'Singleton' so that it always returned the same instance, but that would have been very BAD as every page would then use the same context.
Each service got it's own instance of 'context' through Dependency Injection.
I changed the project so only the controllers got an instance of context through DI. Then, in the controller constructor, this context was passed to the services that the controller had received through dependency injection.
This way, each request only ever uses a single instance of context, but this instance is still short lived, as it is supposed to be as each request has its own context and doesn't share one.
Not sure this is the way it is supposed to work, but given the web app I was working with, this seemed to be the best solution.
I also had to go through and add a 'context.SaveChanges();' statement everywhere a change to the database was made.
Not sure why this should be when the old version of EF did this automatically, but it now works.
Thanks for the advice Derrick

ASP.NET MVC -> WCF -> NHibernate, how to efficiently update entity with data from viewmodel?

A week back, I had an ASP.NET MVC application that called on a logical POCO service layer to perform business logic against entities. One approach I commonly used was to use AutoMapper to map a populated viewmodel to an entity and call update on the entity (pseudo code below).
MyEntity myEntity = myService.GetEntity(param);
Mapper.CreateMap<MyEntityVM, MyEntity>();
Mapper.Map(myEntityVM, myEntity);
this.myService.UpdateEntity(myEntity);
The update call would take an instance of the entity and, through a repository, call NHibernate's Update method on the entity.
Well, I recently changed my logical service layer into WCF Web Services. I've noticed that the link NHibernate makes with an entity is now lost when the entity is sent from the service layer to my application. When I try to operate against the entity in the update method, things are in NHibernate's session that shouldn't be and vice-versa - it fails complaining about nulls on child identifiers and such.
So my question...
What can I do to efficiently take input from my populated viewmodel and ultimately end up modifying the object through NHibernate?
Is there a quick fix that I can apply with NHibernate?
Should I take a different approach in conveying the changes from the application to the service layer?
EDIT:
The best approach I can think of right now, is to create a new entity and map from the view model to the new entity (including the identifier). I would pass that to the service layer where it would retrieve the entity using the repository, map the changes using AutoMapper, and call the repository's update method. I will be mapping twice, but it might work (although I'll have to exclude a bunch of properties/children in the second mapping).
No quick fix. You've run into the change tracking over the wire issue. AFAIK NHibernate has no native way to handle this.
These may help:
https://forum.hibernate.org/viewtopic.php?f=25&t=989106
http://lunaverse.wordpress.com/2007/05/09/remoting-using-wcf-and-nhibernate/
In a nutshell your two options are to adjust your service to send state change information over the Nhibernate can read or load the objects, apply the changes and then save in your service layer.
Don't be afraid of doing a select before an update inside your service. This is good practice anyway to prevent concurrency issues.
I don't know if this is the best approach, but I wanted to pass along information on a quick fix with NHibernate.
From NHibernate.xml...
<member name="M:NHibernate.ISession.SaveOrUpdateCopy(System.Object)">
<summary>
Copy the state of the given object onto the persistent object with the same
identifier. If there is no persistent instance currently associated with
the session, it will be loaded. Return the persistent instance. If the
given instance is unsaved or does not exist in the database, save it and
return it as a newly persistent instance. Otherwise, the given instance
does not become associated with the session.
</summary>
<param name="obj">a transient instance with state to be copied</param>
<returns>an updated persistent instance</returns>
</member>
It's working although I haven't had time to examine the database calls to see if it's doing exactly what I expect it to do.

DataContextProvider

Going from the example given here...
http://ericswann.org/blog/archive/2009/04/06/linq-to-sql-datacontext-provider-revisited.aspx
I'm trying to use the datacontext between the MembershipProvider and the RoleProvider.
For instance, when I call Membership.GetUser(XXXXXX) in the RoleProvider, I get an error because it pulls an item from one datacontext and tries to use it (hence the need for the repository)
But I am ...really stupid, and this is some pretty advanced stuff. Seeing as how I do not get to 'instantiate' the Providers, does anyone have an idea how I might go about using this?
First of all pick your datacontext caching strategy. Use DataContextThreadCache if you're working in winforms, where the context is cached in your running thread context. Use DataContextWebCache if you're working with web apps where the context is cached in HTTP run-time cache.
To register your datacontext look at DataContextProvider.RegisterDataContext and its overloads. Here is an example:
DataContextProvider.RegisterDataContext<YourDataContextType, YourCacheStrategyType>(contextKey, contextConnectionString)
contextKey: is the key you will use to retrieve your data context with.
contextConnectionString: is the connection string for your data context.
This call will use the type of DataContext you specified to create an new instance of it. It will then cache it using the specific caching strategy you specified also. This should probably be called somewhere during the initialization phase of your application. Your repository can then use GetDataContext as outlined in that blog post to get the context instance.

Updating a disconnected LINQ object with MVC Framework RC1

This is a little out there but I have a customer object coming back to my controller. I want to just reconnect this object back to the database, is it even possible? I know there is a datacontext.customers.insertonsubmit(customer), but is there the equivalent datacontext.customers.updateonsubmit(customer)???
This is what I don't like about LINQ-to-SQL.
It generally works fine if you're querying and updating in the same scope, but if you get an object, cache it, and then try to update it later, you can't.
Here's what the documentation says:
Use the Attach methods with entities that have been created in one DataContext, and serialized to a client, and then deserialized back with the intention to perform an update or delete operation. Because the new DataContext has no way of tracking what the original values were for a disconnected entity, the client is responsible for supplying those values. In this version of Attach, the entity is assumed to be in its original value state. After calling this method, you can then update its fields, for example with additional data sent from the client.
Do not try to Attach an entity that has not been detached through serialization. Entities that have not been serialized still maintain associations with deferred loaders that can cause unexpected results if the entity becomes tracked by a second data context.
A little ambiguous IMHO, specifically about exactly what it means by "serialized" and "deserialized".
Also, interestingly enough, here's what it says about the DataContext object:
In general, a DataContext instance is
designed to last for one "unit of
work" however your application defines
that term. A DataContext is
lightweight and is not expensive to
create. A typical LINQ to SQL
application creates DataContext
instances at method scope or as a
member of short-lived classes that
represent a logical set of related
database operations.
So, DataContexts are intended to be tightly scoped - and yet to use Attach(), you have to use the same DataContext that queried the object. I'm assuming/hoping we're all completely misunderstanding what Attach() is really intended to be used for.
What I've had to do in situations like this is re-query the object I needed to update to get a fresh copy, and then do the update.
The customer that you post from the form will not have entity keys so may not attach well, also you may not have every field of the customer available on the form so all of it's fields may not be set.
I would recommend using the TryUpdateModel method, in your action you'll have to get the customer from the database again and update it with the form's post variables.
public ActionResult MySaveAction(int id, FormCollection form)
{
Customer updateCustomer = _Repository.GetCustomer(id);
TryUpdateModel(updateCustomer, "Customer", form);
_Repository.Save(updateCustomer);
}
You will have to add in all your own exception handling and validation of course, but that's the general idea.
You want to use the attach method on the customers table on the data context.
datacontext.customers.Attach(customer);
to reconnect it to the data context. Then you can use SubmitChanges() to update the values in the database.
EDIT: This only works with entities that have been detached from the original data context through serialization. If you don't mind the extra call to the database, you can use the idiomatic method in ASP.NET MVC of retrieving the object again and applying your changes via UpdateModel or TryUpdateModel as #Odd suggests.

Resources