I'm sure this has been answered before, but I've spent the last three hours looking for an acceptable solution and have been unable to find anything, so I apologize for what I'm sure is a repeat.
I have two domain objects, Player and Position. Player's have a Position. My domain objects are POCOs tied to my database with NHibernate. I have an Add action that takes a Player, so I'm using the built in model binding. On my view I have a drop down list that lets a user select the Position for the Player. The value of the drop down list is the Id of the position. Everything gets populated correctly except that my Position object fails validation (ModelState.IsValid) because at the point of model binding it only has an Id and none of it's other required attributes.
What is the preferred solution for solving this with ASP.NET MVC 2?
Solutions I've tried...
Solutions I think might work, I just can't figure out how to do...
So, how do the rest of you solve this?
Thanks,
Dan
PS In my opinion having a PositionId on Player just for this case is not a good solution. There has to be solvable in a more elegant fashion.
Not only to this particular problem, but in general, I would create a separate ViewModel instead of letting the view have the domain model. So, in your case, you don't need to overexpose your domain model (and getting things that you don't needed) to the view, and, nevertheless, turning off validation is most probably the worst solution
创建一个可以为您验证此特殊情况的自定义ModelBinder。
I have had the same issue in one of my applications. I solved it by creating a custom IModelBinder inheriting from DefaultModelBinder and registered it with the particular type I'm binding.
The trick is to use session.Load<>
which only creates a typed reference to the entity without querying the database. ( Read more about session.Load here in Ayende's blog )
/// <summary>
/// Base for binding references. Usually displayed in dropdowns
/// </summary>
public class ReferenceBinder<T> : DefaultModelBinder
where T : class
{
private readonly ISession session;
public ReferenceBinder(ISession session)
{
this.session = session;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var idName = CreateSubPropertyName(bindingContext.ModelName, "ID");
ValueProviderResult result = bindingContext.ValueProvider.GetValue(idName);
int value;
return (int.TryParse(result.AttemptedValue, out value)) ? this.session.Load<T>(value) : null;
}
}
In your example you would do something like this in Global.asax:
ModelBinders.Binders.Add(typeof(Position), new ReferenceBinder<Position>(<pass your current session implementation or use DI/IoC>));
(I'm using Castle Windsor to create the actual binder and populate session in my implementation)
Assuming your domain model is:
public class Player {
public virtual Position Position {get;set;}
}
public class Position {
public virtual int ID {get;private set;}
}
And your postback looks like this:
"Position.ID" = <id from dropdown>
EDIT: You should probably use a DTO approach with dedicated view models. I've learned this later on. Have a look here for a quick start .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.