Preventing EF6 from validating related entities - entity-framework-6

I have code similar to this in my Cities controller:
if (!ModelState.IsValid)
return BadRequest(ModelState);
var city = DbContext.Cities.SingleOrDefault(o => o.CityId == cityId);
DbContext.Entry(city).State = EntityState.Modified;
city.name = "test";
DbContext.SaveChanges();
City has a foriegn Key to State. When it hits SaveChanges, it's erroring because the properties on the virtual State entity are all null. How do I get it to not validate the State entity? I have specifically NOT included the state entity in the SingleOrDefault as it's not relevant. I suppose I could load it but then I'd have to load all related entities, when I just want to edit the city name. How do I fix this?

Turns out it was an Editor inheritance bug.
I had this in my cities model:
public virtual State State { get; set; } = new State();
Removing the = new State() did the trick.

Related

Remove form parameter from binding

I have a form with some fields, and depending of the data i dont want to save all to database.
lets say, i have this controler
public ActionResult Edit([Bind(Include = "id,Costumer, City ,Obs")] Clients clients)
{
if (ModelState.IsValid)
db.Entry(clients).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(clients);
}
but i somecases i dont want to save the City.
How can i remove the City from being save to database ?
I've tryied with
ModelState.Remove("City");
but it keeps saving to database
If City is a navigation property, then something like:
db.Entry(clients.City).State = EntityState.Unchanged;
if City is a string then
db.Entry(clients).Property("City").IsModified = false;

EF lookup items being added when they already exist

I'm pretty sure this isn't a duplicate question (or I don't know how to ask it properly) so here goes. I have an ASP.NET MVC project using EF 6.1. In it I have an entity called Member. The Member has a property called Races that can contain one or more Race entities. The Races property on Member:
public virtual ICollection<Race> Races { get; set; }
The Race entity:
public class Race : ILookupListItem {
public int Id { get; set; }
public string Description { get; set; }
public bool Active { get; set; }
[JsonIgnore]
public virtual ICollection<Member> Members { get; set; }
}
The Race entity is what I have always called a lookup.
My issue arises when I try to save the entity after updates have occurred on the client. My SaveMember controller method is below along with my business logic method for actually saving the entities. (To avoid any confusion, InjectFrom is the ValueInjecter method and the JSONResponseError and JSONResponseSuccess classes are our custom wrappers around a JsonResult.)
public JsonResult SaveMemberInfo(MemberInfoModel model) {
try {
// retrieve member
var member = new Member();
member.InjectFrom(model);
var races = new List<Race>();
races.InjectFromList(model.Races);
member.Races = races;
// save member
var savedMember = _members.UpdateMember(member, out errId);
var savedModel = GetMemberChartViewModel(savedMember);
// notify user of success
return new JsonResponseSuccess(savedModel);
}
catch (Exception ex) {
return new JsonResponseError(message);
}
}
The _members.UpdateMember method is below.
public Member UpdateMember(Member contract, out int? errId) {
try {
using (_db = new ApplicationContext(_currentUserID)) {
// updates entity state in the context using the entity's State field from Julie Lerman's example on MSDN.
_db.FixState();
_db.SaveChanges();
errId = null;
return contract;
}
}
catch (Exception ex)
{
// log error to db and return id
errId = LogError(ex, "MemberLogic.UpdateMember");
return null;
}
}
When I get the data contract back from the UpdateMember method, the Races property has all the races saved to the memeber before the update, plus any that I just saved (so it's adding but not doing a diff to determine which items were already there and which were removed). In addition the Races table will now have duplicate entries for the "new" races. My assumption is that this isn't EF's default behavior but I've never worked with a dropdown list that populated a list of items, usually it's just a single property (like Gender or Country). Is there something obvious I'm missing?
Thanks!
EDIT: It just occurred to me that the EntityConfiguration for the Member and Race intersection table would be useful, added below. Obviously, this is only the part I thought to be relevant to the question.
HasMany(t => t.Races).WithMany(t => t.Members).Map(m =>
{
m.ToTable("MemberRaces", "dbo");
m.MapLeftKey("MemberId");
m.MapRightKey("RaceId");
});

Updating many-to-many relationship entity framework

I have problem with updating entites that have many-to many relationship. Below my User and category class:
public class User : IEntity
{
[Key]
public virtual long Id { get; set; }
private ICollection<Category> _availableCategories;
public virtual ICollection<Category> AvailableCategories
{
get { return _availableCategories ?? (_availableCategories = new List<Category>()); }
set { _availableCategories = value; }
}
}
public class Category : IEntity
{
[Key]
public long Id { get; set; }
/// <summary>
/// Full name or description of a category
/// </summary>
[StringLength(255)]
public string FullName { get; set; }
}
This is code snippet from my repository
public override void Edit(User user)
{
var dbUser = _context.Users.Include(x => x.AvailableCategories)
.Single(x => x.Id == user.Id);
var categories = _context.Categories;
dbUser.AvailableCategories.Clear();
foreach (var cat in user.AvailableCategories)
{
dbUser.AvailableCategories.Add(cat);
}
_context.Entry(dbUser).State = EntityState.Modified;
}
However the categories don't get updated. What EF does is insert empty rows into category table and sets relations to this new rows with user.
How can I update User so that I change only categories that already exist in the database?
User that I pass to Edit method has AvailableCategories with only Ids set (rest of properties are empty).
When you're doing something like posting back M2M relationships, you either must post the full object, as in every single property on those objects, or simply post a list of ids and then use those to query the associated objects back from the database. Otherwise, Entity Framework understands your purpose to be to update the properties on the objects as well, in this case with empty values.
Obviously the first option is quite unwieldy, so the second way is the preferred and standard way. Generally, for this, you'd want to use a view model so you could have a property like the following, that you would post into:
public List<long> SelectedCategories { get; set; }
But, if you insist on using the entity directly, you can get much the same result by simply doing:
var selectedCategories = user.AvailableCategories.Select(m => m.Id)
Once you have the ids:
var newAvailableCategories = _context.Categories.Where(m => selectedCategories.Contains(m.Id));
And then finally set that on your user:
dbUser.AvailableCategories = newAvailableCategories;
I notice you are also adding the user.AvailableCategories directly into dbUser.AvailableCategories. I've noticed when binding back complex objects from an MVC view that DB Entities are no longer attached to the DbContext. If you look at the entity, you can verify by checking dbContext.Entry(cat).State is "detached" (or something unexpected) I believe.
You must query those entities back out of the dbContext (possibly by using the returned cat.Id's). Or otherwise manually set the entities as "unchanged". And then add those "non-detached" items into dbUser.AvailableCategories. Please see Chris's answer as it shows with specific code how to get this done.
Also, I might use a linking entity. Possibly something like this:
public class UserCategory
{
public User User {get;set;}
public Category Category {get;set;}
}
And add it to DB context. Also, drop the linking lists in your current User and Category class. This way you can manipulate the UserCategory class (and DbSet) to manage your many-to-many relationship.

How to Create a Run-Time Computed (NotMapped) Value in Entity Framework Code First

I have a user class in EF Code First that contains a lot of properties, and each user has a collection of "Contacts" which are other users as a subset of the total user population. The other collection "ContactOfOthers" is just the reverse showing who has this user as a contact as this is a many-to-many relationship.
public class User {
[Key]
public string UserName { get; set; }
// Lots of other properties not relevant to this question...
[NotMapped]
public bool IsMyContact { get; set; }
public virtual ICollection<User> Contacts { get; set; }
public virtual ICollection<User> ContactOfOthers { get; set; }
}
I introduced a not-mapped (not mapped to DB) property called IsMyContact. This is for cases when the user queries for a bunch of users and I need to show in the View which users are already in their contacts list. So this property should be true if the User is part of their "Contacts" collection. It shouldn't be saved to the DB since it can be different for the same user, depending on the user doing the query.
Is there a nice way to do this in a query from the context? It could of course be brute-forced by doing two queries then iterating through the main one, looking for matches to the user's Contacts collection, but I'm wondering if there's a more elegant way to do this from one query, projecting a run-time computed column onto this property?
I don't know a way how to populate the IsMyContact property in the User directly within the query. But an alternative approach could be to introduce a ViewModel which wraps the User and has in addition the IsMyContact flag:
public class UserViewModel
{
public bool IsMyContact { get; set; }
public User User { get; set; }
}
(The class User would not have the IsMyContact flag anymore.)
You could then project into this type when you run your query:
string me = "That's me"; // name of the user who is selecting
List<UserViewModel> list = context.Users
.Where(u => ...some filter...)
.Select(u => new UserViewModel
{
IsMyContact = u.ContactOfOthers.Any(c => c.UserName == me),
User = u
})
.ToList();
The benefits would be: You need only one round trip and you are not forced to load the whole collection of Contacts to determine the IsMyContactFlag (but you can if you want to).
The drawback: You need this additional ViewModel type.
It is possible to do this but it will be far from a "nice way" because you cannot return instances of your User type. You must write custom linq-to-entities query and you must solve two problems:
You cannot project to mapped types in linq-to-entities
You cannot access non mapped properties in linq-to-entities
So my high level untested idea about doing this is:
var query = from u in ctx.Users
where u.Id != id // don't include current user - you can add other condition
join c in ctx.Users
.Where(x => x.Id == id) // current user
.SelectMany(x => x.Contacts)
on u.Id equals c.Id into leftJoin
from y in leftJoin.DefaultIfEmpty()
select new
{
UserName = u.UserName,
IsMyContact = y != null
};
This should be a query which will load pairs of UserName and information if the user is contact or not. If you want User instance instead you must do something like this:
var users = query.AsEnumerable()
.Select(new User
{
// Project to list in linq-to-objects
});

ASP.NET MVC - Partially updating model from view

I just wondered how people were approaching this situation. It's something that seems like a weak point in my usage of MVC with ORMs (NHibernate in this case)...
Say you have a fine-grained and complicated entity in your model. You will likely have an admin page to manage objects of this type. If the entity is complicated, it is unlikely that you will be modifying the whole entity in one form. You still need to pass the relevant properties to the view, and incorporate changes to those properties in the model when the view returns them.
What does anyone do in this situation?
Create a view model which is (or contains) a subset of the entities properties. Pass this to and from the view. In 'edit' action method in controller, get the object from repository, go though all the properies in the ViewModel and apply them to the Model object (model.a = viewmodel.a, modelb = viewmodel.b). This seems the obvious sensible route, but generates a lot of tedious plumbing code. Also this complicates validation a bit.
Something else?
I've looked briefly at automapper - but this doesn't seem to fit the bill exactly, maybe I'm wrong?
Thanks.
This sounds like the perfect scenario for automapper. You create a view model class which contains a subset of the fields or your real model, and you let AutoMapper take care extraccting values from the domain model object into your view model object. What issues are you having with this approach?
Consider this example:
Here is your domain model and your view model
public class Person
{
public string FirstName
{ get; set; }
public string LastName
{ get; set; }
public string HomeNumber
{ get; set; }
public string Address1
{ get; set; }
public string Address2
{ get; set; }
}
public class PersonViewModel
{
public string FirstName
{ get; set; }
public string LastName
{ get; set; }
public string HomeNumber
{ get; set; }
}
Here is your mapping, you have to create a mapping in both directions from dm->vm and vm->dm.
From what I've seen when using Automapper is that if you map from object A to B and B has a property which A doesn't have, it will be reset. So when I create the map I direct it to ignore those missing properties. I'm not a Automapper expert so I may be using it wrong.
Mapping
Mapper.CreateMap<Person, PersonViewModel>();
// Automapper will reset values in dest which don't exist in source, so be sure to ignore them!
Mapper.CreateMap<PersonViewModel, Person>()
.ForMember(dest => dest.HomeNumber, opt => opt.Ignore());
Finally usage:
Person p = new Person()
{
FirstName = "First",
LastName = "Last",
Address1 = "add 1",
Address2 = "add 2"
};
PersonViewModel pvm = Mapper.Map<Person, PersonViewModel>(p);
// Map to a new person
Person p2 = Mapper.Map<PersonViewModel, Person>(pvm);
// Map to the existing person just to update it
Person p3 = new Person()
{
HomeNumber = "numberHere"
};
// This will update p3
Mapper.Map<PersonViewModel, Person>(pvm, p3);
Because of the exclusion, this is obviously less than ideal, but much better than manually doing the whole thing.
Have your view model map one-to-one with your domain model.
Specify Model as argument for the routeValues as below. This means your view model will be initialized with the values from the domain model. Only the sub set of fields in the form will be overwritten in the resulting personViewData.
Update View:
#model ViewModel.PersonView
#using (Html.BeginForm("Update", "Profile", Model, FormMethod.Post))
{
...Put your sub set of the PersonView fields here
}
ProfileController:
public ActionResult Update(string userName)
{
Person person = _unitOfWork.Person.Get().Where(p => p.UserName == userName).FirstOrDefault();
PersonView personView = new PersonView();
Mapper.Map(person, personView);
return View(personView);
}
[HttpPost]
public ActionResult Update(PersonView personViewData)
{
Person person = _unitOfWork.Person.Get().Where(p => p.UserName == personViewData.UserName).FirstOrDefault();
Mapper.Map(personViewData, person);
_unitOfWork.Person.Update(person);
_unitOfWork.Save();
return Json(new { saved = true, status = "" });
}
Why don't you use TryUpdateModel with the form collection.
If your view is editing a person
public class Person
{
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Address { get; set; }
}
And your view is only editing first name and last name, you can do this:
public ActionResult Action(FormCollection form)
{
Person personToUpdate = Repository.GetPerson(form["ID"]);
TryUpdateModel<Person>(personToUpdate, form);
Repository.Update(personToUpdate)
return View();
}
That will only update Person with the items that a part of the form collection. If you don't want a field updated, don't submit it with the form.
What if you have full model but each page uses and updates only the required part? Then you update the business model using complete view data at the last page.
I use a similar approach to yours (in my case Entity Framework) with Entity -> ViewModel -> View but only on views with "complex" entities that have either 1:M or M:M relationships. In most cases I took the low road and went for Entity->View when I have a simple entity.
My ViewModel is defined as Entity+supporting properties: SelectList or MultiSelectList and either a string or List<string>. I'll also use a ViewModel for instances where I have properties I need for the view but may not necessarily need in the entity (database).
Http Get controller methods are straightforward ActionResults with return View(repository.FetchNewViewModel()) for Create or repository.FetchModelById(id) for Edit. In both instances I'm initializing my entities before passing them to the view.
Create([Bind(Exclude = "Entity.EntityId")] ViewModel model) and Edit(ViewModel model) are the Http Post controller methods of Create and Edit. My Edit view has a hidden input field for EntityId to pass it back and forth.
By the time the Http Post method has the viewmodel, I lose all Entity.Relation and ViewModel.(Multi)SelectList values. I have to rebuild the object if I want my view to display properly:
`
try
{
var tags = model.TagIds; // List<string> or <int> depending on your Id type
if (model.TagsList == null) // It will be
{
model.TagsList = _repository.FetchSelectedTags(tags); // Build a new SelectList
}
if (!ModelState.IsValid)
{
return View(model);
}
_repository.Add(model.Article, tags); // or Save() for Edit
}
catch
{
return View(model); // Generally means something screwed in the repository class
}
return RedirectToAction("Index");
`
There is maybe 30% of my entity base using a ViewModel so I definitely only use it as needed. If you have complex views and model data in most instances you can probably break it down to smaller views.
Right now i´m working on a large project using S#arp Architecture and im also using the approach:
Model -> ViewModel -> Model
I use the ViewModel for the Binding part and Validations, the other approach is to use the Model Directly (with tryUpdateModel / UpdateModel which we used during the prototype develop) but for complex scenarios we end up handling special situation like SelectLists/Checkbox/Projections/HMAC Validations in a little ViewModel anyway and using a lot of Request.Form["key"] =( , the other drawback is handling the errors situations where you want to repopulate the form with the user input, i found it a little more complicated using the Model directly (using a ViewModel we take a lot of advantage of ModelState attempted value, saving us a couple of trips to the DB, anyone who have faced this scenario will know what i mean).
This approach is a bit time consuming, just like you said, you end up matching properties, but in my opinion is the way to go for complex forms.
It worth mentioning that we just use ViewModels for the Create/Edit scenarios, for almost everything else we use directly the model.
I have not use autommapers so far, but definitely i ll give it a try.

Resources