I have mvc view that has some columns from entity. When I do db.SaveChanges(), all columns that are not part of the view are being updated with NULL, so overwriting any values that were present in database record. That's very lame.
I am aware that I could do ModelView for the the view and bind just those columns that i want. But I am looking for a way to simply tell EF, to 'ignore' columns during this particular update, to NOT update columns that are NOT present in the MvC View.
I am using EF 5. Any suggestions?
I don't know why you want to avoid creating a separate Model but i guess you know what you are doing so maybe try this approach to trick EF into thinking the properties have not changed:
var entry = context.Entry(obj);
entry.Property(name).IsModified = false;
I haven't tried it myself but it should be possible in EF 5. If it doesn't work try accessing the property entry by searching the entry.CurrentValues.PropertyNames collection and then setting the IsModified to false.
I think what i needed is this
User u = db.Users.Find(user.UserID);
if (u!=null) {
TryUpdateModel(u);
if (ModelState.IsValid)
{
db.SaveChanges();
}
Related
I'm using EF database first and with MVC.
I'm wanting to add some validation on a property to compare its old value to its new one and report a validation error to the MVC ModelState if there is a problem.
This would be easy enough using code first and validating using 'set' on the property. However I can't do this using database first because its auto generated.
I've looked at using IValidatableObject and the validate() method however by then the value has already been changed on the property so I can't see the old one anymore to compare to.
Short of creating a method to pass the new value into first to check it, I can't think of another way.
Any suggestions?
Thanks
If you want to compare a new value to an old value then you are going to have to grab the values from the database first (before updating) and compare them:
[HttpPost]
public ActionResult Update(MyObject myObject)
{
var oldObject = db.Objects.FirstOrDefault(o => o.Id == myObject.Id);
//Compare oldObject.Value to myObject.Value
}
You could still use IValidatebleObject and pass in the objects that you need to keep that logic outside the controller.
Its not the ideal and this has started illustrating some of the weaknesses in Model and DB first but here's how I ended up doing it.
I decided to change the property in my model so that set was private and then create a separate method in the partial class to set the value. The validation is then all done in that method.
Thanks for your help anyway
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();
}
I've got a LINQ to SQL object, and I want to group the selected data and then pass it into a view. What's the correct way of doing this? I'm sure I need to group the data when I select it rather than grouping it in the view, as this will result in about 200 rather 50000 rows I need to pass into my view. Are there any good examples of this online that anyone has seen?
Cheers
MH
-----edit-----
I want a bit of both:-
for example, my data object has (amongst others) 2 properties I want to extract, and group on, ItemDetail.ItemID and ItemDetail.Label - it is a set of those I want to pass into my view. My data factory returns a IQueryable which will contain (in live) about 100 records for each ItemID/Label combination, and thus I want to group this in my view so that it only shows 1 row per ItemID/Label combination.
Also, how do I type my View - I have tried passing in something like the var xxx = ...; return View(xxx); but I'm not sure how to strongly type (if I can) the view properly. I can probably boj this and get it working, but I wanted to do this correctly.
----edit 2----
I've just got a bit further on this.
using the var IQueryable itemDetList
itemDetList = itemDetList.OrderBy(i => i.ItemID).GroupBy(i => i.ItemID).Select(i => i.First());
produces a grouped list, with 1 row per ItemID, and preserves the object typing so that I can pass it into a strongly-typed view - is that the correct way of manipulating the data? How can I put another layer of grouping so that it groups by .Label within each .ItemID group?
You may want to abstract the model you pass to your view from the LINQ 2 SQL objects; check out the View Model Pattern. If this means you find yourself potentially writing lots of code to map properties from LINQ 2 SQL objects to your View Model objects then consider using AutoMapper.
Well, then group the data and pass it onto your View from your Controller...
public ViewResult Foo()
{
var data = this.GetGroupedData();
return this.View(data);
}
private IEnumerable<Bar> GetGroupedData()
{
return from x in GetData()
group x by x.Baz into g
select new Bar(g.Key);
}
I would define Presentation-Models that represent your groups in your View. Fill the Presentation-Models with LINQ and pass them to your View.
With Presentation-Models you have strongly typed data to display in your view.
Let's say I have a product object (pretty much empty) and I bind it to a Product view. Then I click update in the view. In my CustomModelBinder my bindingContext.Model is always null on the update request. Is there a recommended way of me retrieving the prior model at this point or do I always have to recreate it?
You have to recreate it from the form fields. The values you bound to the model for the GET are long gone.
perhaps im not understanding your needs to use a CustomModelBinder, but did u concider Data Annotations Model Binder yet?
it even comes with (serverside) validation based on simple statements like [Required] which u can put right inside your model, see this
I have a site where I'm using fluentNhibernate and Asp.net MVC. I have an Edit view that allows user to edit 8 of the 10 properties for that record (object). When you submit the form and the Model binds, the two un-editable fields come back in the view-model as Empty strings or as default DateTime values depending on the type of property.
Because I'm also using AutoMapper to map my view-model to my Domain Entity, I cannot just load a fresh copy of my object from the database and manually set the 2 missing properties. Whats the best way to persist those fields that I don't want edited?
One way that does work is to persist the values in hidden Input fields on my View. That works but feels gross. I appreciate any recommendations. Is there a way in my AutoMapper to configure this desired functionality?
UPDATE:
Ok, So I guess I'm not trying to ignore the fields, I'm trying to make sure that I don't persist null or empty string values. Ignoring the fields in AutoMapper does just that, they get ignored and are null when I attempt to map them before Saved to my repository.
The asp.net mvc DefaultModelBinder is extensible, and you can override it to create your own binding schema. But this will involve more work than two "hidden Input fields", which , in my point of view, is not that gross.
You can tell Automapper to ignore the 2 properties:
Mapper.CreateMap<Source, Destination>()
.ForMember(dest => dest.SomeValuefff, opt => opt.Ignore());
Possible related question.
Can you use the AutoMapper.Map overload that also accepts TEntity?!
entity = Mapper.Map(viewmodel, entity);
As long as you do not have the properties on your viewmodel, it won't change the values on your entity. It takes the entity being passed in and applies only the properties from the viewmodel back to the entity.