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

Multi-Column dropdown in ASP.NET MVC
Glimpse Heads Up Display is not showing up when debugging in VS 2017
How to create a controller in VS 2017 Core
Asp.net mvc5 online calendar
Cannot implicitly convert type 'string' to 'tblOpenAct'
Azure Mobile App on Service Fabric
How Intellisense updated in in razor files (.cshtml)
How to pass model (Asp.net MVC) as a datasource for jQuery DataTables
ASP.NET MVC - Model binding for generated form inputs
MVC Fist Load Data
Serve MVC View from a byte array
pass model to view and back to a new controller
Validation issues for DateTime in cloud
Unable to retrieve metadata for 'MVCMusicStore.Models.Album
MVC set project properties from code behind
Deploying MVC project to remote iis server with Umbraco

Categories

HOME
ssl
rtmp
apacheds
localforage
genetic-algorithm
restsharp
telerik
range
wav
librsvg
aac
command-line-interface
tapi
lighttpd
pyfftw
message
rtp
accelerated-mobile-page
man
azure-ad-graph-api
py4j
ssms-2014
google-oauth2
php-carbon
smallbasic
unsigned-integer
paket
trial
stomp
seh
lifecycle
presto
docker-image
qweb
bezier
wso2iot
pac
free-diameter
uifont
tpl-dataflow
kony
derbyjs
glumpy
zenity
cabal-install
atmosphere.js
perspective
proc
file-management
visual-build-professional
facebook-comments
vimeo-ios
google-api-ruby-client
pakyow
parsoid
clipping
actioncable
openejb
gulp-rename
user-registration
telescope
bloodhound
linegraph
mks
bit.ly
gnat
razor-2
laravel-validation
symfony-2.5
citymaps
mui
pkcs#10
nhunspell
keyboard-navigation
acts-as-taggable-on
array-address
libavcodec
re2c
nsusernotificationcenter
angularjs-module
alternate-data-stream
oncreate
hiphop
nextpeer
arr
boost-gil
springboard
sdl.net
bubble-popup
emacs-ecb
xmltextwriter
jtemplates
orthographic
paredit
xoom
server.transfer
stsadm

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