Let me explain the whole context:
I'm using ASP.NET MVC 2, EF4 (POCO).
I trying to do a generic repository for my app.
I'm having problem on updating a many to many relationship.
I have an item that is related to other by a many to many table. In the View, the user picks the desired Categories, and send just the chosen id's to the Controller.
Then, the Controller queries the Category Repository, adding it to the main item:
item.Categories.Add(CategoriesRepository.Single(id);
But, when I go the Repository and try to save like this:
Entities.ApplyCurrentValues(entity);
Context.SaveChanges();
But, the state of my entity is Added.
Then, I Cannot save my entity :(.
How can I solve this problem?
Thanks for your answers.
I have in the View, the following code:
<%= Html.CheckBoxList("Categories", ((IEnumerable<Categories>)ViewData["Categories"]).ToDictionary(c => c.ID.ToString(), c => c.Name)
, Model.Categories.ToDictionary(c => c.ID.ToString(),c => c.Name )) %>
Where CheckBoxList is a HTMLHelper.
Im putting the ids as values in the View, because I dont know other way to put and then get this information from the View.
How can I use the ObjectStateManager.ChangeRelationshipState method?
Like this? :
itemRepository.Db.ObjectStateManager.ChangeRelationshipState(item, item.Categories, "Categories", System.Data.EntityState.Modified);
I trying in this way, but it returns error.
Help! lol
You've got a few problems.
1) ApplyCurrentValues only works for scalar-properties. Since your trying to add a Category to the Categories navigational property on Item, this will not work.
2) You say this:
the user picks the desired Categories, and send just the chosen id's to the Controller.
How can your Controller accept a bunch of id's? How is this model binding done? We need more info on how your View is bound to your model, what's being passed to the action method. But it sounds like you need to redesign this particular View with the help of a ViewModel.
3) Change tracking with POCO's in MVC is a royal pain in the butt. In your scenario, you'll need to use ObjectStateManager.ChangeRelationshipState to manually set the Categories relationship to **Modified.
Honesty though, it's more pain than it's worth. I went through this same problem.
Cop it on the chin - go grab the entity first and use Controller.UpdateModel:
[HttpPost]
public ActionResult Item(Item item)
{
// get the existing item
var existingItem = ItemRepository.Single(item.Id);
// use MVC to update the model, including navigational properties
UpdateModel(existingItem);
// save changes.
Context.SaveChanges();
}
Related
Just a rookie in .NET MVC world and still learning
I created three EF models in framework, one is clients, one is order, and items, below is the relation:
Client Order Items
PK:ID PK Order.id PK Items.ID
... FK:Client.id ...
FK:Item.id
In this case I wanna display all the client information and the item details they've bought in one table, obviously I cannot use any DBcontext here. So what should I do to combine the three table's info and output that? Create a new model on those three?
Any ideas or article are very welcomed!
I would create a ViewModel with all of the Data that you want to display. This is the model that will get populated in the controller and then it would get passed to the View.
So in the View it would use the ViewModel and wouldn't need to know about the underlying Database Model.
And in the Controller you would get the data needed and populate the ViewModel and pass that model onto the View.
Here is a page with an examples. There are plenty more out there too. http://sampathloku.blogspot.com/2012/10/how-to-use-viewmodel-with-aspnet-mvc.html
I have a bunch of tables. Each table has a "Status" column. The column has either the character A or I. A= Active and I= Inactive.
I have a create view corresponding to each table. I want to display a dropdownbox that shows two values- Active and Inactive and then map them accordingly.
I know I can do following in each view where I need the dropdown for status
#Html.DropDownListFor(model => model.status, new SelectList(new[] { new { ID = "A", Desc = "Active" }, new { ID = "I", Desc = "Inactive" } }, "ID", "Desc"))
however if tomorrow I decide to have add one more status i will have to change each and every view.
The other option is to create a dictionary and pass it through a view model sort of as explained in this article
however that means I have to create a viewmodel for each of my models just to accomodate the statuslist.
is there any other way I can achieve this?
I recommend using a View Model for each unique View. Long term it makes the UI easier to work with and maintain.
The View Model approach can be taken to an extreme and become counterproductive in my experience. For example, when creating a VM for a Customer Entity, I do not recreate a CustomerVM that has all the same properties of the Customer Entity. Instead, I just create a Customer Property on the CustomerVM that holds the entire Customer Entity. Some may disagree with this approach because I may be exposing more info to the View than it needs, if the view is not displaying all of the Customer Entity info. It's true, but I like solutions that are fast and easy to implement and maintain.
You never know what is going to be necessary in the future. Over time I have found this approach to be the most flexible solution.
So, then you could create a Base View Model for all views that have common look-up lists and have your new View Models inherit from this Base VM.
It's one way to do it. :)
Following link might be helpful for binding the dropdown list in mvc
http://www.c-sharpcorner.com/UploadFile/deveshomar/ways-to-bind-dropdown-list-in-Asp-Net-mvc/
I have just started using MVC 2 , I have got a couple of queries , may be you guys can help me to clear my confusion.
Why mvc doesnt allows to inherit multiple models on a view page.
For instance if i inherited account model in my view , why i cant excess the associated entity properties with the account model in that view, We are only allowed to use the properties of that model like <%: Model.FirstName :%> Where First name is the property of account model. Why we cannot use <%:Model.account.aspnet_users.vehicle.make %> Where aspnet_users is associated with account through a foreign key vice versa. MVC 2 only allows <%:Model.account.aspnet_users.vehicle %> Therfore I cant use the associated property of vehicle which in this case is vehicle.make. I was thinking of doing something like <%: Html.TextboxFor(model => model.account.aspnet_users.vehicle.make %>.
ASP.NET MVC doesn't restrict navigation to related properties. If you cannot access the property it means either:
The relation is not loaded (it is null) and lazy loading is turned off / context is disposed
The relation is actually a collection an you must use Linq to navigate in the collection
I'm using NerdDinner as a guide for my first MVC/LINQ to SQL project. It discusses the use of the ViewModel pattern when a View needs data from multiple sources - in their example: Dinners and Countries (serves as the drop down list).
In my application, the problem is a bit different. It's not so much different data, rather data linked via a key constraint. I have a Story table that links to aspnet_users via the UserId key. I would like to have easy access to the UserName for each story.
Since I'm using the repository pattern and returning IQueryable in some cases for deferred execution, I'm struggling with the correct way to shape the data. So I'm using this VideModel pattern right now to make it work but not sure if it's the right way.
Instead of returing IQueryable Story (which wouldn't work since I need the UserName), I'm returning a new custom class UserStory, which has a Story property and a string Username property.
What are your thoughts?
It seems like your question has less to do with MVC as it is simply a question about how to access the story data based on the username string.
Would it be possible to create a view in your database with all the UserStory data, the username, along with userid in it? That way, you could select from the view based on the username you have.
To create the view, you would simply have to do a join between the user table and the userstory table based on the userid.
After that, you could still use the repository pattern with the IQueryable being returned.
If you are wanting to do updates, it would be simple to do since you still have the userid, and would be able to link back to the actual table which would need the update.
If you look at Kigg, you will see that they mess about with the initial model to create custom ViewModels. That's the thing that NerdDinner doesn't cover in any detail. You could create a StoriesWithUserName class that inherits from Stories, but adds a new property - UserName. Then you return that to your View which would inherit from IEnumerable<StoriesWithUserName>
[EDIT]
Oops. Didn't spot that you already did this :o)
Using the repository pattern and returning an IQueryable of Stories is fine. The relationship allows you to access the the username value something like this >>
Assuming you are returning the IQueryable in your model object:
foreach(Story story in Model.Stories)
{
// do something with the value
response.write(story.aspnet_user.UserName);
};
Your Repository method would look like this:
public List<Stories> GetStories(Guid UserId)
{
return datacontext.Stories.Where(u => u.UserId = UserId).ToList();
}
The relationship will automatically provide you with access to the UserName value in the foreach loop i first mentioned. nothing more is required.
I'm not sure why your pagination control failed on Count() though??
Hope this helps
Situation: In some project management software written in asp.net I have a create project page (working fine). I need to add to this the ability to add tasks from a list of templates to this project pre-creation BUT the list of available tasks is dependent on some values sitting in the create form.
My abstract solution is this:
I have a "Create" view and an "Add Tasks" View - both strongly typed to a composite viewModel defined in the controller
My Create method checks which button was used to call it - if the
button was "Add Tasks" it then renders the AddTasks view, passing the model in from the create view, again all in the same controller.
The AddTasks View posts to the Create view with one of two buttons, one loads the view and the other causes an actually DB save.
My Problem is this:
The different views use different properties of the same model, but in passing this model between them, the data is reset (in any case reload or save).
I am guessing this is happening from auto binding of data - though I thought fields not present on the form would not overwrite existing model data passed down.
There is hardly any code in the controller manipulating the model at present - It is only passed from view to view in these cases.
This is the controller code:
// POST: /Project/Create/<viewModel>
[Authorize, AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id,id")] ProjectViewModel model)
{
if (model.SubmitValue == "Create")
{
try
{
model.Project.Id = Guid.NewGuid();
model.Save(this.User.Identity.Name);
return this.RedirectToAction("Details", new {id = model.Project.Id});
}
catch (Exception e)
{
this.ModelState.AddModelError(e.ToString(), e.ToString());
}
return View(model);
}
if(model.SubmitValue == "AddTasks")
{
return this.View("AddTasks",model);
}
return this.View(model);
}
//POST: /Project/AddTasks/ + model
[Authorize, AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddTasks([Bind(Include = SelectedCarrierTasks")]ProjectViewModel model)
{
return View(model);
}
The Question is: How do I maintain the state of the model across these views until it finally save it?
I would prefer to avoid any hackish (TempData) or JS dependant solutions, but I am not closed to these if they are really the best solution.
Thanks,
Adam Tolley
One simple solution is to persist the ViewModel object in a Session variable and bind the View from this source.I ts certainly not the most elegant solution. Another option, and probably less elegant one is persist this model data in the database, with some temporary/unsaved flag.
The problem is that when you display the add tasks view you're not providing fields for your "Project" object therefore the ModelState loses the data related to the project, you will need to provide this fields to ensure you're not loosing that data.
You don't need to display this fields they can be of type hidden and they will preserve the value. Just make sure that if you will be binding to a view model you will need to name this fields correctly like this Model.Project.Property.
Perhaps I am trying to solve the wrong problem (ala Bruce Eckel). I am going to try to move to a structure that needs this sort of fuzzy boundary less. I don't want to adopt a REST paradigm only to shoe-horn it into a stateful application.
Possibly these controls belong on the same page, and I can use some JQuery goodness to put in a tab pane for easiness on the eyes.
Thanks to those who answered, I found each useful and will try to remember to up-vote them as soon as I have some more rep.
I can't comment on other peoples questions at the moment, but the only real option is the session if you want to persist an objects state during web requests, or serializing it and placing it in a hidden field.
Or a final option would be to change the way your pages work so you can save the object after each request...
If your using nHibernate then you might want look into the Conversations pattern, but this just essentially saves the nHibernate session into the asp.net session anyway...