Reputation: 1128
I'm calling three Models (Unit, Site, Work_Type) in my view model called UnitAdminViewModel. I need to set one field as required from the Unit Model. Since I'm using Database First approach, I cannot modify the Unit Model directly since this gets autogenerated. How can I successfully add:
[Required(ErrorMessage = "Group is required")]
public string GroupName { get; set; }
to my view model UnitAdminViewModel?
public class UnitAdminViewModel
{
public Unit Unit { get; set; }
public List<Site> Site { get; set; }
public IEnumerable<Work_Type> Work_Type { get; set; }
}
In the Unit Model, I want to set the field GroupName as [Required]
public partial class Unit
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Unit()
{
this.Staffs = new HashSet<Staff>();
}
public int UnitID { get; set; }
public string UnitCode { get; set; }
public string UnitName { get; set; }
public string GroupName { get; set; }
public byte IncentiveUnit { get; set; }
public bool CallCenter { get; set; }
public bool CDWUnit { get; set; }
public string CDWSite { get; set; }
public Nullable<int> SiteID { get; set; }
public Nullable<int> DivisionID { get; set; }
public bool WFCUnit { get; set; }
public bool QAMonitored { get; set; }
public bool NICEMonitored { get; set; }
public string ListPrefix { get; set; }
public string TSHSource { get; set; }
public string StatsSource { get; set; }
public string DialerSource { get; set; }
public Nullable<int> CostCenterID { get; set; }
public int WaterfallView { get; set; }
public bool Locked { get; set; }
public string Platform { get; set; }
public Nullable<int> Supplier { get; set; }
public string Work_Type { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Staff> Staffs { get; set; }
}
Update
I tried going off @Izzy example. I feel like i'm closer, but the [Required] still doesn't seem to trigger a validation error when I submit a form without populating that field. @Izzy, is there something I might be missing?
View Model
public class UnitAdminViewModel
{
public Unit Unit { get; set; }
public List<Site> Site { get; set; }
public IEnumerable<Work_Type> Work_Type { get; set; }
}
UnitMetaData class
[MetadataType(typeof(UnitMetaData))]
public partial class Unit
{
}
public class UnitMetaData {
[Required(ErrorMessage = "Group is required")]
public string GroupName { get; set; }
[Required(ErrorMessage = "UnitName is required")]
public string UnitName { get; set; }
public string CDWSite { get; set; }
public string Platform { get; set; }
public Nullable<int> Supplier { get; set; }
public string Work_Type { get; set; }
}
VIEW
@model WebReportingToolDAL.Models.ViewModels.UnitAdminViewModel
@{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Unit</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Unit.UnitName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Unit.UnitName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Unit.UnitName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Unit.GroupName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Unit.GroupName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Unit.GroupName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Unit.CDWSite, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.Unit.CDWSite, new SelectList(Model.Site, "SiteName", "SiteName"), new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Unit.Platform, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.Unit.Platform, new List<SelectListItem> { new SelectListItem { Text = "PSCC", Value = "PSCC" }, new SelectListItem { Text = "RC", Value = "RC" } }, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Unit.Supplier, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.Unit.Supplier, new List<SelectListItem> { new SelectListItem { Text = "0", Value = "0" }, new SelectListItem { Text = "1", Value = "1" } }, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Unit.Work_Type, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.Unit.Work_Type,new SelectList(Model.Work_Type, "Name", "Name"),new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "UnitID,UnitCode,UnitName,GroupName,IncentiveUnit,CallCenter,CDWUnit,CDWSite,SiteID,DivisionID,WFCUnit,QAMonitored,NICEMonitored,ListPrefix,TSHSource,StatsSource,DialerSource,CostCenterID,WaterfallView,Locked,Platform,Supplier,Work_Type")] Unit unit)
{
if (ModelState.IsValid)
{
unit.UnitCode = "XX";
unit.IncentiveUnit = 1;
unit.CallCenter = true;
unit.CDWUnit = true;
unit.DivisionID = 2;
unit.WFCUnit = false;
unit.QAMonitored = false;
unit.NICEMonitored = true;
unit.ListPrefix = null;
unit.TSHSource = null;
unit.StatsSource = null;
unit.DialerSource = null;
unit.CostCenterID = 3;
unit.WaterfallView = 1;
unit.Locked = false;
var siteId = (from s in db.Sites
where s.SiteName.ToLower().Equals(unit.CDWSite.ToLower())
select s.SiteID).First();
unit.SiteID = siteId;
db.Units.Add(unit);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(unit);
}
Upvotes: 0
Views: 3410
Reputation: 239290
You can use a real view model, for one. Simply wrapping a bunch of entities in a class is missing the point of what view models are for. Your view models should only contain the properties that should be displayed/edited and it should hold the business logic for your view, such as the fact that GroupName
is required (when it apparently isn't at the database level).
That means creating something like:
public class UnitViewModel
{
// other properties you want to edit
[Required]
public string GroupName { get; set; }
}
Then, you use this rather than Unit
in your view, and map the posted properties from UnitViewModel
onto your Unit
instance.
Upvotes: 2
Reputation: 6866
When using Database first approach you'll realise that the class is marked as partial
So what you can do is make use of MetadataType
attribute to achieve what you're after.
So go ahead and create a file and name it e.g. UnitMetaData
. Your code should look something like:
public class UnitMetaData
{
[Required(ErrorMessage = "Group is required")]
public string GroupName { get; set; }
//more properties
}
Your Unit
class is partial so you can create it another file and use MetadataType
as:
[MetadataType(typeof(UnitMetaData))]
public partial class Unit
{
}
More about MetadataType
here
partial
definition:
It is possible to split the definition of a class or a struct, an interface or a method over two or more source files. Each source file contains a section of the type or method definition, and all parts are combined when the application is compiled.
Please Note: Ensure the namespace
is same as the generated Unit
class, otherwise it will not work
Upvotes: 4