MVC Trouble Deleting a record - asp.net-mvc

I get an error when trying to delete a record:
InvalidOperationException - The object cannot be deleted because it was not found in the ObjectStateManager.
public ActionResult Delete(CustomerModel customer)
{
db.Customer.Remove(customer);
db.SaveChanges();
return View();
}
Update: I checked in the bebugger, customer is completely empty..And therefore the database isn't able to delete that specific record.
Any ideas why?

Your customer object was not loaded into the DbContext called db (I'm assuming it's a DbContext... not entirely clear from your code).
With Entity Framework, the DbContext you are using has to be aware of an object it is acting on. It looks like you created customer in some manner other than by loading it into db.
You can add it to the DbContext like this:
db.Attach(customer);
Then, proceed to remove it and save your changes.
For more details see
http://blogs.msdn.com/b/adonet/archive/2011/01/29/using-dbcontext-in-ef-feature-ctp5-part-4-add-attach-and-entity-states.aspx
Specifically for your case the paragraph Attaching an existing entity to the context
Update (based on your update)
How did you create customer in the first place? Without that detail, it's just guesswork to understand why it's completely empty.

Related

Asp mvc 3 noobie: Why is the code-first method not building my DB on sql server?

I am an ASP MVC 3 noobie who has done a few tutorials. Now I'm trying to build a site. All of the tutorials on the microsoft website emphasize the code-first approach: you define your model with code and then create a datacontext and then the entity framework creates/manages the DB based on your code.
I set up an Employees class and a DataBaseContext class that inherits from DbContext. I added a connection string to Web.config connection string that successfully links DataBaseContext to an already existing empty DB on SQL server. EDIT= That was the problem. See my answer below
But when I try to run the Employees controller created thru scaffolding, I get this error
Invalid object name 'dbo.Employees'.
Description: An unhandled exception occurred during the execution of...
Exception Details: System.Data.SqlClient.SqlException: Invalid object name 'dbo.Employees'.
I followed this post SqlException (0x80131904): Invalid object name 'dbo.Categories' and realized that if I create an employees table on the DB, this excpetion goes away (I get a new one saying that the column names are invalid).
But I thought the whole point of MVC 3 is that the framework will make the DB for you based on the code.
Maybe I need a line of code in the Global.asax Application_start() to create the database? Here is my application_start method:
Sub Application_Start()
AreaRegistration.RegisterAllAreas()
RegisterGlobalFilters(GlobalFilters.Filters)
RegisterRoutes(RouteTable.Routes)
End Sub
Here is the code for Employee:
Public Class Employee
Property EmployeeID As Integer
Property First As String
Property Last As String
Property StartDate As DateTime
Property VacationHours As Integer
Property DateOfBirth As DateTime 'in case two employees have the same name
End Class
Here is the code for the DB context:
Imports System.Data.Entity
Public Class DatabaseContext
Inherits DbContext
Public Property Employee As DbSet(Of Employee)
Public Property AnnualLeave As DbSet(Of AnnualLeave)
End Class
What am I missing?
By default EF uses DropCreateDatabaseIfModelChanges<TContext> database initializer. Accordingly to the MSDN:
An implementation of IDatabaseInitializer<TContext> that will delete, recreate, and optionally re-seed the database with data only if the model has changed since the database was created. This is achieved by writing a hash of the store model to the database when it is created and then comparing that hash with one generated from the current model.
Since the database was created manually, EF can't find the hash and decides do not perform any further initialization logic.
You might want to look into this article, same question successfully answered already.
Or it can be this (also resolved successfully)
Answer to your problem is most likely one of the two.
Hope this will help you
Does the name you're specifying for your connection string match the name of your database context?
For example:
Context
var myDbContext = new MyDbContext();
Connection string
<connectionStrings>
<add name="MyDbContext" connectionString="YOUR.CONNECTION.STRING" providerName="System.Data.SqlServer" />
</connectionStrings>
Try and see if this post I wrote about DbContext with MVC works for you: Code-First
Not a lot to be done to get this to work, but there are a few things that are easily missed that will cause a bunch of head aches.
hope this helps
I had already created a database with that name on SQL server. Once I deleted the existing database, the code first framework created the tables for me like it was supposed to. It seems like if the database already exists, the framework won't set up the tables for you. It wants to create the whole DB from scratch.
You were using AdventureWorks Database?
It has it's own schema assigned to the employees table. HumanResources.Employees and not the default dbo.Employees.
Even though I've identified the problem, I don't know the solution to using the database as configured with the HumanResources schema.
Anybody know?

Change model after database is created on EF4 code only

Hey, sorry for my bad english...
Using EF4 code-only, I have created some POCO classes and my database was generated from that. All worked fine, I inserted some data on the tables but now I need to create a new property on one of my classes. If i just create it, the application give me the exception:
{"The model backing the 'TestContext' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the RecreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data."}
I tried to create manually the field on the table, but it is still complaining... does someone know if there is a way and if so how can I manually update the database schema (i don't want to recreate it because i already have data) to match the model?
It should work if you make sure that your new column match exactly your new property.
For example, if you add a property NewProp
public class MyEntity
{
[Key]
public int Id;
public string PropA;
public int PropB;
public int NewProp;
}
then in your database table MyEntities, you would add a column NewProp of type int not null.
What you can do to check if the column you add is correct, is to rename your database, then let Code-First recreate the database and see what's different between the original and new databases.
EF generates partial classes. So you can add new properties(fields) in another partial class.

Why should I use GetOriginalEntityState() in my LINQ To SQL repository save method?

I'm looking at an example of a save method in a Products repository from Steven Sanderson's book, Pro ASP.NET MVC 2 Framework:
public void SaveProduct(Product product)
{
// if new product, attach to DataContext:
if (product.ProductID == 0)
productsTable.InsertOnSubmit(product);
else if (productsTable.GetOriginalEntityState(product) == null)
{
// we're updating existing product
productsTable.Attach(product);
productsTable.Context.Refresh(RefreshMode.KeepCurrentValues, product);
}
productsTable.Context.SubmitChanges();
}
I do not understand the logic in the else if line:
else if (productsTable.GetOriginalEntityState(product) == null)
As I understand it, GetOriginalEntityState() returns the original state of the specified entity.. in this case that entity is product.
So this else if statement reads to me like: "If an original doesn't exist then..." but that doesn't make sense because the book is saying that this checks that we are modifying a record that already DOES exist.
How should I understand GetOriginalEntityState in this context?
Edit
By the way, this excerpt came from chapter 6, page 191... just in case anyone has the book and wants to look it up. The book just has that function in the code sample but it never explains what the function does.
This is a little bit of a guess since I have never actually used GetOriginalEntityState but the question peaked my interest to figure out what is going on.
I think the intent here is to check that product is still attached to the original DataContext
The line:
if (productsTable.GetOriginalEntityState(product) == null)
I think this will return null if product has been dettached or created manually and not handled by the DataContext.
From MSDN:
This method returns the original state
of an entity since it was either
created or attached to the current
DataContext. The original state of an
entity that has been serialized and
deserialized must be provided by an
independent tracking mechanism and
supplied when the entity is attached
to a new DataContext. For more
information, see Data Retrieval and
CUD Operations in N-Tier Applications
(LINQ to SQL).
I think the key line to understand is:
This method returns the original state
of an entity since it was either
created or attached to the current
DataContext.
GetOriginalEntityState is used so that the method can receive an object with the option of not being attached already to the DataContext. Attached meaning, returned by a Linq To SQL call vs just creating an instance like Product p = new Product() { ... };. If it is not attached, it will attach it to the DataContext and keep any of the values that were modified (preserving the update values) due to the RefreshMode.KeepCurrentValues param.
Then the productsTable.Context.SubmitChanges(); always happens since even if it is dettached, the GetOriginalEntityState will make sure it gets attached so the submit will work.

ASP.NET MVC 2: Updating a Linq-To-Sql Entity with an EntitySet

I have a Linq to Sql Entity which has an EntitySet. In my View I display the Entity with it's properties plus an editable list for the child entites. The user can dynamically add and delete those child entities. The DefaultModelBinder works fine so far, it correctly binds the child entites.
Now my problem is that I just can't get Linq To Sql to delete the deleted child entities, it will happily add new ones but not delete the deleted ones. I have enabled cascade deleting in the foreign key relationship, and the Linq To Sql designer added the "DeleteOnNull=true" attribute to the foreign key relationships. If I manually delete a child entity like this:
myObject.Childs.Remove(child);
context.SubmitChanges();
This will delete the child record from the DB.
But I can't get it to work for a model binded object. I tried the following:
// this does nothing
public ActionResult Update(int id, MyObject obj) // obj now has 4 child entities
{
var obj2 = _repository.GetObj(id); // obj2 has 6 child entities
if(TryUpdateModel(obj2)) //it sucessfully updates obj2 and its childs
{
_repository.SubmitChanges(); // nothing happens, records stay in DB
}
else
.....
return RedirectToAction("List");
}
and this throws an InvalidOperationException, I have a german OS so I'm not exactly sure what the error message is in english, but it says something along the lines of that the entity needs a Version (Timestamp row?) or no update check policies. I have set UpdateCheck="Never" to every column except the primary key column.
public ActionResult Update(MyObject obj)
{
_repository.MyObjectTable.Attach(obj, true);
_repository.SubmitChanges(); // never gets here, exception at attach
}
I've read alot about similar "problems" with Linq To Sql, but it seems most of those "problems" are actually by design. So am I right in my assumption that this doesn't work like I expect it to work? Do I really have to manually iterate through the child entities and delete, update and insert them manually? For such a simple object this may work, but I plan to create more complex objects with nested EntitySets and so on. This is just a test to see what works and what not. So far I'm disappointed with Linq To Sql (maybe I just don't get it). Would be the Entity Framework or NHibernate a better choice for this scenario? Or would I run into the same problem?
It will definately work in Entity Framework that comes with .NET 4 (I'm doing similar things in the RC version)
This does not explain the exception but:
You should dispose the ObjectContext that's (most likely) wrapped in your repository. The context caches items, and should only be used for a single unit-of-work.
Try to use a pattern like:
public ActionResult Update(int id, MyObject obj) // obj now has 4 child entities
{
using(var repository = CreateRepository())
{
var obj2 = _repository.GetObj(id);
if(TryUpdateModel(obj2))
{
repository.SubmitChanges();
}
else
.....
}
return RedirectToAction("List");
}
When fetching items, create a new repository as well. They are cheap to create and dispose, and should be disposed as quickly as possible.

Inserting data based on ParentID, strange behavior ASP.NET MVC?

I have a simple form which inserts a new Category with the given parentID (ServiceID).
and my parent child relationship is this;
Service > Category
my url for creating a Category based on the ServiceId is this
/Admin/Categories/Create/3 => "3 is the serviceID"
and my Action method is this
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(int? id, Category category)
{
if (ModelState.IsValid)
{
try
{
category.Service = dbService.GetAll().WithServiceId(id.Value).SingleOrDefault();
dbCategory.Add(category);
dbCategory.Save();
return RedirectToRoute("List_Categories", new { ServiceId = id.Value });
}
catch
{
ModelState.AddRuleViolation(category.GetRuleViolations());
}
}
return
View ....
I am using LinqToSql for db actions. Anyway the strange part begins here.
When i save the data it inserts a data to Service table instead of insterting data just to Category Table and the data which is inserted to Category Table has the new inserted ServiceID.
Is it a problem with the ASP.NET MVC ModelBinder or am i doing a mistake that i dont see ?
I have used LinqToSql in several projects and have never had an issue like this
It could be an error in your LINQ To SQL set up. Is the service id an autogenerated field in the DB -- is it marked as such in the LINQ to SQL classes? Does your service disconnect it from the data context, then not reattach it before submitting? If so, have you tried adding the category to the service and then saving the updated service?
var service = ...
service.Categories.Add(category);
service.Save();
Where does your Category object come from? As I see you are relying on ASP.NET MVC Model binding for providing it but for that you need a form somewhere to make a POST. It would help to see the form too.
Also personally I rather use FormCollection (rather than business model classes) in my action signatures and then pull the posted data out from the FormCollection by myself. Coz sooner or later you end up having some complex objects with various one-to-many, many-to-many relationships that Model Binding just won't pick up and you have to construct it by yourself.

Resources