asp.net-mvc


Saving entities with foreign key in ASP.NET MVC


I need some help doing something I am assuming is simple. I am using ASP.net MVC 3 with CodeFirst (CTP5)
I have two entities: Company and Location. A Company can many Locations. The classes are as follows (stripped of all needless info)
public class Company
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
public class Location
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public virtual Company Company { get; set; }
}
Now in my controller, I only allow creating a Location within the context of a Company, so the Company Id is always passed in (In the View, I show the name of the Company in a read only field, but do not allow the user to change/edit that.
public ActionResult Create(int companyId)
{
Company company = _session.Single<Company>(c => c.Id == companyId);
Location newLocation = new Location {Company = company};
return View(newLocation);
}
[HttpPost]
public ActionResult Create(Location location)
{
if (ModelState.IsValid)
{
_session.Add<Location>(location);
_session.CommitChanges();
return RedirectToAction("Index");
} else {
return View(location);
}
}
Now whenever I try to create a new location, the ModelState.IsValid is always false due to the fact that location.Company.Name is not supplied and is a required field on Company. I am never trying to create a new company here, I merely trying to create a location with a reference to the correct company. I don't want to add the Name property to the view just to get the ModelState to validate. How can this be accomplished easily? Should I be passing something different from the view? or to the view?
As i was explaining in my comment, i stumbled upon a small change which makes this work, still think it is a kludge as I dont see why i need to duplicate the child Id paramater, but the best/simplest one I could find that should be easy to update in the future and I will be the first to admit I dont know all (or most) of what there is in CodeFirst.
I changed the location class from:
public class Location
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public virtual Company Company { get; set; }
}
To:
public class Location
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
}
Now as far as I can tell, this hasnt changed the database schema at all, but now the only thing which is required on the Location (when validating) is that there is an ID in the CompanyId field, the Company property can be left null (before, it was trying to validate a proper Company since the Company class was required).
So now when creating a Location, the only thing the view needs to pass back in the CompanyId.
Anyone see any drawbacks? or a better way?
You can easily just add a hidden field with company name on your form. Its data will get picked up and sent to your POST action as expected.
If you don't use company name on the server side at all, you can fill this hidden field up with any dummy text as long as company ID is correct (because you use it). But if you do need correct company name with your ID, you'll have to fill actual name into hidden field instead of some dummy text.
Anyway. This will add a hidden field for your company name
<%= Html.HiddenFor(m => m.Company.Name) %>
and if you don't have your Company property set to anything then, you can as well use this:
<%= Html.Hidden("Company.Name", "Super duper company") %>
Whether this value is an actual name or a dummy name it doesn't really matter. Your model will be valid upon postback.
Regular postback or Ajax?
I suppose you're using a regular postback and not an Ajax postback. If you do use Ajax one and you're using jQuery and calling $.post() or $.ajax() or something similar, you can always provide whatever object you like. You can fill any value for the company name in your JavaScript code.
If you have complex objects in JavaScript and would like to send them to your controller action with strong type parameters (so they will be validated) you can use this little jQuery plugin of mine, that prepares any JSON object to be correctly sent to Asp.net MVC action so data will be automatically data bound to your strong types to get validated. Does JavaScript dates as well. :)
Additional information
Since you pointed out (in a comment) that your entities are very much work in progress and you may be adding/removing required fields, this may be very tedious to also change all related views.
Yet there are ways you may take, to make your life a bit easier when it comes to changable models and different validation scenarios depending on object state:
Have separate view models for creation process that also include functionality to auto-convert to application model class:
public class LocationCreate
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int CompanyId { get; set; }
public Location ToModelInstance()
{
return new Location {
Id = this.Id,
Name = this.Name,
Company = new Company {
Id = this.CompanyId,
Name = "Super duper company Ltd." // you can as well omit this line
}
};
}
}
Use inheritance:
public class CompanyBase
{
public int Id { get; set; }
}
public class Company : CompanyBase
{
[Required]
public string Name { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
public class Location
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public virtual CompanyBase Company { get; set; }
}

Related Links

Updating View with changed ViewModel after Form Post
ASP.Net MVC Core 1.0, how avoid reencoding characters from inside a partial view
How do I add a period after #viewDataTeam.ID to display an image?
Azure AD login session time out
HttpPost Delete MVC for Composite Keys
MVC validation doesn't work on partial view
how to load hundred of images to bootstrap asp.net mvc by LazyLoad jQuery Plugin
Publishing asp.net mvc website to windows container giving error
Difference between jQuery Validation and Microsoft jQuery Unobtrusive
Publishing mvc5 C# publish folder work on developer machine but not on other?
how to join the list string in single line using comma?
Read emails from Inbox gmail
Application not auto creating AccountController
Need transparent borders on kendo popup modal
Check if another action filter attribute is being used in action in MVC 5
DropDownListFor is not selecting existing value

Categories

HOME
bootstrap-4
opencl
runnable
load
react-navigation
bolt-cms
cql3
feed
xquery
logback
intel-xdk
delphi-xe7
webdriver-io
base
drag
h2o
silverlight
cross-compiling
command-line-interface
openmodelica
lighttpd
installer
org-mode
durandal-2.0
oracle11gr2
rational
lexikjwtauthbundle
atg
similarity
rgdal
amazon-cloudfront
burp
google-oauth2
flatbuffers
rdf4j
debugview
pymysql
panel-data
imageshack
apex-code
ose
folly
xaf
bezier
cookiestore
sagepay
btle
dxgi
mdanalysis
free-diameter
program-slicing
oracle-aq
android-calendar
docker-swarm-mode
clientscript
mrtg
derbyjs
abbyy
column-oriented
liclipse
glumpy
android-camera-intent
ifc
dr-memory
blocking
redux-framework
olingo
tealeaf
dashing
visual-build-professional
ios-frameworks
python-3.1
winobjc
webmail
accounts
multiple-files
xelement
clientid
wchar-t
double-quotes
vbo
pencilblue
android-design-library
words
modern-ui
cvs2git
mklink
symfony-2.5
bessel-functions
cpp-netlib
dynamic-typing
data-quality
mydbr
azimuth
disabled-input
prudentia
external-dependencies
shift
libnids
semantic-markup
google-authorship
source-highlighting
headless-browser
ed
etrade-api
queryanalyzer
sqlitemanager
templatebinding

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App