ASP.NET display related detail records via Razor - asp.net-mvc

I am new to asp.net and c#, I have been trying to duplicate and app done in php using MVC3, generating the code from the same database. I have a question about showing the detail records in my "Details" view.
namespace MvcApplication5.Models
{
[DataContract(IsReference = true)]
[KnownType(typeof(masterDomain))]
[KnownType(typeof(masterFIP))]
[KnownType(typeof(masterSFPF))]
[KnownType(typeof(rgCountiesServed))]
[KnownType(typeof(rgKeyword))]
[KnownType(typeof(rgServicesProvided))]
public partial class rgOrganization
{
public rgOrganization()
{
this.rgCountiesServeds = new HashSet<rgCountiesServed>();
this.rgKeywords = new HashSet<rgKeyword>();
this.rgServicesProvideds = new HashSet<rgServicesProvided>();
}
[DataMember]
public int orgID { get; set; }
[DataMember]
public string ORGANIZATION { get; set; }
[DataMember]
public string CONTACT_PERSON { get; set; }
[DataMember]
public string PHONE_NUMBER { get; set; }
[DataMember]
public string FAX_NUMBER { get; set; }
[DataMember]
public string EMAIL_ADDRESS { get; set; }
[DataMember]
public string WEBSITE { get; set; }
[DataMember]
public string STREET_1 { get; set; }
[DataMember]
public string STREET_2 { get; set; }
[DataMember]
public string CITY { get; set; }
[DataMember]
public string ZIP_CODE { get; set; }
[DataMember]
public string COUNTY { get; set; }
[DataMember]
public string FIPS { get; set; }
[DataMember]
public string MAILING_ADDRESS { get; set; }
[DataMember]
public Nullable<int> SFPF { get; set; }
[DataMember]
public Nullable<int> DOMAIN { get; set; }
[DataMember]
public virtual masterDomain masterDomain { get; set; }
[DataMember]
public virtual masterFIP masterFIP { get; set; }
[DataMember]
public virtual masterSFPF masterSFPF { get; set; }
[DataMember]
public virtual ICollection<rgCountiesServed> rgCountiesServeds { get; set; }
[DataMember]
public virtual ICollection<rgKeyword> rgKeywords { get; set; }
[DataMember]
public virtual ICollection<rgServicesProvided> rgServicesProvideds { get; set; }
}
View Code
#model MvcApplication5.Models.rgOrganization
#{
ViewBag.Title = #Html.DisplayFor(model => model.ORGANIZATION);
}
#section Scripts {
<script type="text/javascript"
src="http://maps.google.com/maps/api/js?sensor=false"></script>
}
<h2>#Html.DisplayFor(model => model.ORGANIZATION)</h2>
<h3><span id="mailing_address">
#Html.DisplayFor(model => model.MAILING_ADDRESS)
</span></h3>
<fieldset>
<legend> #Html.DisplayFor(model => model.COUNTY) COUNTY</legend>
<div class="display-field">
<strong>#Html.DisplayFor(model => model.ORGANIZATION)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(model => model.CONTACT_PERSON)
</div>
<!-- would like to display services provided here -->
</fieldset>
My question is how do I access the 'rgCountiesServeds'and 'rgServicesProvideds' via Razor?

They appear to be members of your model.
So you can access the collection as
model.rgServicesProvided
To iterate through the collection, do something like this:
#foreach (var serv in model.ServicesProvided) {
Service is #serv.ToString()<br/>
}
Replace serv.ToString() with whatever property you want to display.

If I understand what you're asking, you can access the rgCountiedServeds and rgServicesProvideds just like the other properties of rgOrganization. They are collections and properties of your model so you can loop over them in the View or create a drop down list for each of those properties. I.e.,
#Html.DropDownList("DropDownCounties", Model.rgCountiesServeds)

Related

Rendering partial view ASP MVC

I want to render a partial view within the main view.
This is what I have done so far, but non of the code not loading the partial view.
Can anyone help me with this? Thanks in advance.
This is my main model
public class AppRequest
{
[Key]
public int Id { get; set; }
[Required]
[Display(Name = "Request Type")]
public int ReqType { get; set; }
[Required]
[Display(Name = "Requesting By")]
public int Req_By { get; set; }
[Required]
[Display(Name = "Requesting Date")]
public DateTime Req_Date { get; set; } = DateTime.Now;
[Required]
[Display(Name = "Request Location")]
public int Req_Location { get; set; }
[Required]
[Display(Name = "Request Heading")]
public string Req_Heading { get; set; }
[Display(Name = "Cover Note")]
public string Req_CoverNote { get; set; }
[Required]
[Display(Name = "Company Name")]
public int Company_Id { get; set; }
public virtual IList<Purchase> Purchase { get; set; }
public virtual IList<General> General { get; set; }
[NotMapped]
public Purchase PurchaseItem { get; set; }
}
#region Purchase
public class Purchase
{
[Key]
public int Id { get; set; }
[Required]
[ForeignKey("AppRequest")]
public int Req_Id { get; set; }
public virtual AppRequest AppRequest { get; set; }
public virtual IList<PurchasingEmpl> PurchasingEmpl { get; set; }
public virtual IList<PurchasingItems> PurchasingItems { get; set; }
}
public class PurchasingEmpl
{
[Key]
public int Id { get; set; }
[Required]
[ForeignKey("Purchase")]
public int Purchase_Id { get; set; }
public virtual Purchase Purchase { get; set; }
public int Emp_Id { get; set; }
public bool Status { get; set; }
}
public class PurchasingItems
{
[Key]
public int Id { get; set; }
[Required]
[ForeignKey("Purchase")]
public int Purchase_Id { get; set; }
public virtual Purchase Purchase { get; set; }
public int Supp_Id { get; set; }
public int Itm_Description_Id { get; set; }
public decimal Unit_Amount { get; set; }
public byte[] Attachment { get; set; }
public decimal Qty { get; set; }
public string Recomandation { get; set; }
public bool Status { get; set; }
public bool Settled { get; set; } = false;
public string PoNo { get; set; }
}
#endregion
And this is the View. My partial view name is "_Purchasing". So under this _Purchasing partial view, I have added another 2 partial views. So I need to load this main partial view to show the other details.
#model Asp_PASMVC.Models.AppRequest
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>AppRequest</h4>
<hr />
<div id="PurchseReq">
#Html.Partial("_Purchasing");
</div>
</div>
}
you can use #RenderPartial and #Partial
#RenderPartial vs #Partial
As mentioned, you can incorporate a partial view in a Razor view by using either of two methods: #RenderPartial or #Partial. The difference between the two methods may look small and harmless, but it may bite at you if you don’t know how to handle it.
The key difference between the two methods is that Partial returns a HTML-encoded string while #RenderPartial is a void method that writes directly to the response output stream. The usage of the two methods is slightly different:
#Html.Partial("_yourPartialView")
#Html.RenderPartial("_yourPartialView")

ASP.NET MVC 5 ValidationMessageFor for a foreign key

I have following model classes, using VS 2017, EF and MVC 5.0
public class Album
{
public virtual int AlbumId { get; set; }
public virtual int GenreId { get; set; }
public virtual int ArtistId { get; set; }
public virtual string Title { get; set; }
public virtual decimal Price { get; set; }
public virtual string AlbumArtUrl { get; set; }
public virtual Genre Genre { get; set; }
public virtual Artist Artist { get; set; }
}
public class Genre
{
public virtual int GenreId { get; set; }
[Display(Name="Genre Name")]
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual List<Album> Albums { get; set; }
}
In the View, I have following code
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.AlbumId)
<div class="form-group">
#Html.LabelFor(model => model.GenreId, "GenreId", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("GenreId", String.Empty)
#Html.ValidationMessageFor(model => model.GenreId)
</div>
</div>
When I run the code through VS, the view is displayed with GenreId with a dropdown list box. The dropdown includes a blank value , in addition to the values present in the table Genre.
When I select blank from the dropdown and click "save", an error message is displayed
GenreId field is required
I don't understand where the message is coming from.
In the model class Album, there is no Required annotation for the GenreId property. So how does ASP.NET MVC know to validate the GenreId?
Also, why is a blank value displayed in the dropdown list ?
public class Album
{
public virtual int AlbumId { get; set; }
public virtual int GenreId { get; set; }
public virtual int ArtistId { get; set; }
public virtual string Title { get; set; }
public virtual decimal Price { get; set; }
public virtual string AlbumArtUrl { get; set; }
public virtual Genre Genre { get; set; }
public virtual Artist Artist { get; set; }
}
According to your poco class GenreId have to be int value and can not be null.
if you write like this in the below, you generate non-required field.
public virtual Nullable<int> GenreId { get; set; }
Lastly, Razor and MVC can generate default error message if you use or etc.
#Html.ValidationMessageFor()
Note: You use string.empty in the second parameter. This parameter can set default value of Dropdown.
#Html.DropDownList(,string.empty)
Hva a nice coding ;)

Eager loading Not retrieving data for child class MVC

I have the following classes defined in my project
public class PolicyDocs
{
[Key]
[Required]
[MaxLength(20)]
public string PolicyDocID { get; set; }
[DisplayName("Date Revised")]
public DateTime DateRevised { get; set; }
[MaxLength(500)]
[DisplayName("Document Name")]
public string DocumentName { get; set; }
[MaxLength(10)]
[DisplayName("Version")]
public string VersionNo { get; set; }
[MaxLength(255)]
[DisplayName("Location")]
public string DocumentPath { get; set; }
public string CategoryID { get; set; }
public ICollection<PolicyDocumentsCatagory> PolicyDocumentsCatagory { get; set; }
}
and
public class PolicyDocumentsCatagory
{
[Key]
[MaxLength(20)]
//[Required]
public string CategoryID { get; set; }
[MaxLength(20)]
[Required]
[DisplayName("Description")]
public string CategoryDesc { get; set; }
[DisplayName("Active")]
public Boolean IsActive{ get; set; }
}
Data is properly loaded in to the table .
Example:
PolicyDocs:
1 ,"12-Jan-2017", "Document 1","version 1",100
PolicyDocumentsCategory:
100, "Information Technology", "true".
I am using the following query in my Controller Class
_context = new ApplicationDbContext();
//PolicyDocs _Policy = new PolicyDocs();
var _LPolicies = _context.PolicyDocs.Include(i=> i.PolicyDocumentsCatagory).ToList();
return PartialView("_GetAllPolicies", _LPolicies);
While running the query I am unable to see any data loaded for PolicyDocumentsCategory in "_LPolicies" object. The query is loading data in table "PolicyDocs".
Nor I am able to reference the PolicyDocumentsCategory in VIEW. I can not see the properties of "PolicyDocumentsCatagory" in the view
#model IEnumerable< MyRTOCloud.DBModels.PolicyDocs>
<div class="row">
<div>
<table id="Categories" class="table table-hover">
<thead>
<th>Category</th>
<th>Document Name</th>
<th>Release Date</th>
<th>Version</th>
</thead>
#foreach (var lp in Model)
{
<tr>
<td>#lp.PolicyDocumentsCatagory.____</td> // I can not see any peroprty of "PolicyDocumentsCatagory"
<td>#lp.DocumentName </td>
<td>#lp.DateRevised </td>
<td>#lp.VersionNo </td>
</tr>
}
</table>
</div>
</div>
Thanks,
PolicyDocumentsCatagory is a collection and you have to iterate it in itself or in your case you can combine with a separator as a string.
So, try something like that;
<td>#string.Join(",", lp.PolicyDocumentsCatagory.Select(x => x.CategoryID))</td>
Your PolicyDocs class is referencing a single CategoryID leading me to assume this is a one-to-many relationship (PolicyDocs being the many, PolicyDocumentsCatagory being the one). If that is the case, you will want to change your PolicyDocumentsCatagory property in PolicyDocs to public virtual PolicyDocumentsCatagory PolicyDocumentsCatagory { get; set; }. Note the virtual part. This is what allows EF to populate the relationship property automatically.
public class PolicyDocs
{
[Key]
[Required]
[MaxLength(20)]
public string PolicyDocID { get; set; }
[DisplayName("Date Revised")]
public DateTime DateRevised { get; set; }
[MaxLength(500)]
[DisplayName("Document Name")]
public string DocumentName { get; set; }
[MaxLength(10)]
[DisplayName("Version")]
public string VersionNo { get; set; }
[MaxLength(255)]
[DisplayName("Location")]
public string DocumentPath { get; set; }
public ICollection<PolicyDocumentsCatagory> PolicyDocumentsCatagory { get; set; }
}
public class PolicyDocumentsCatagory
{
[Key]
[MaxLength(20)]
public string CategoryID { get; set; }
[Required]
[MaxLength(20)]
public string PolicyDocID { get; set; }
[ForeignKey]
public PolicyDocs PolicyDocs { get; set; }
[MaxLength(20)]
[Required]
[DisplayName("Description")]
public string CategoryDesc { get; set; }
[DisplayName("Active")]
public Boolean IsActive{ get; set; }
}
Your models are not valid. You need to have a foreign key in your PolicyDocumentsCatagory that referencing to PolicyDocs and there is no need for CategoryID in PolicyDocs.
One PolicyDocs has many PolicyDocumentsCatagory, while one PolicyDocumentsCatagory is referenced to only one PolicyDocs. Standard one to many relationship type.

How to fill dropdownlist for MVC4 razor views (C#)

UserProfiles Model
[Table("Users")]
public class UserProfiles
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
//public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public string Initials { get; set; }
public string Company { get; set; }
public string Department { get; set; }
public string Title { get; set; }
public string Team { get; set; }
public string TeamSub { get; set; }
public string Phone { get; set; }
public string ImageLocation { get; set; }
public string Note { get; set; }
public string Comment { get; set; }
}
Controller
public ActionResult Index()
{
**EDIT :** ViewBag.ProfileId = new SelectList(db.UserProfiles, "UserName", "UserName");
return View(db.UserProfiles.ToList());
}
In the View ( i hope / believe here is the issue )
#model IEnumerable<OilNGasWeb.Models.UserProfiles>
#{
ViewBag.Title = "CLS - Oil & Gas Web Site Users";
}
<h2>Web Site Users</h2>
**Removed** #Html.DropDownList(Model => Model.UserName,Model.UserName)
**Changedinto** #Html.DropDownList("UserName", String.Empty)
New Error:
Exception Details: System.InvalidOperationException: There is no ViewData item of
type 'IEnumerable<SelectListItem>' that has the key 'UserName'.
Add a SelectList to your ViewBag in the Controller:
ViewBag.ProfileId = new SelectList(db.UserProfiles, "Id", "Username");
then add this in your View:
#Html.DropDownList("ProfileId", String.Empty)
Moreover you should have used "model" instead of "Model" in your lambda expression.

Error while accessing the Navigation Property in EF Code First

I am having a simple ViewModel which have something like this...
ViewModel
public class UserPostCommentViewModel
{
public virtual List<Comment> Comment { get; set; }
public virtual User User { get; set; }
public virtual Post Post { get; set; }
}
so that i can return a view which has 1 Post with the details 1 User details and Many Comments submitted by users....
POST
[Key]
[ScaffoldColumn(true)]
public int PostID { get; set; }
[Required(ErrorMessage="Required")]
[StringLength(250)]
public string Title { get; set; }
[Required(ErrorMessage="Required")]
[DataType(DataType.MultilineText)]
public string Body { get; set; }
[DataType(DataType.Date)]
public DateTime DateCreated { get; set; }
[DataType(DataType.Date)]
public DateTime DateModified { get; set; }
[ScaffoldColumn(false)]
public int UserID { get; set; }
[ScaffoldColumn(false)]
public int? TagID { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public virtual User Users { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
Comment
[Key]
[ScaffoldColumn(true)]
public int CommentID { get; set; }
[DisplayName("Your Comment")]
[DataType(DataType.MultilineText)]
public string Body { get; set; }
[DataType(DataType.Date)]
[ScaffoldColumn(true)]
public DateTime DateCreated { get; set; }
[ScaffoldColumn(true)]
public int PostID { get; set; }
[ScaffoldColumn(true)]
public int UserID { get; set; }
public User User { get; set; }
public Post Posts { get; set; }
USer
[ScaffoldColumn(true)]
[Key]
public int UserID { get; set; }
[StringLength(15)]
[DisplayName("First Name")]
[Required(ErrorMessage="First Name is Required")]
public string FirstName { get; set; }
[StringLength(15)]
[DisplayName("Last Name")]
[Required(ErrorMessage = "Last Name is Required")]
public string LastName { get; set; }
[DataType(DataType.EmailAddress,ErrorMessage="please enter valid email")]
[DisplayName("Email Address")]
[Required(ErrorMessage = "Email is Required")]
[Remote("CheckUniqueEmail","User",ErrorMessage="An account with this email address already exists.")]
public string Email { get; set; }
[DataType(DataType.Password)]
[Required(ErrorMessage = "Password is Required")]
public string Password { get; set; }
[DataType(DataType.Date)]
[ScaffoldColumn(true)]
public DateTime JoiningDate { get; set; }
[DataType(DataType.Date)]
[ScaffoldColumn(true)]
public DateTime? LastActivityDate { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
i have a StronglyTyped View with the ViewModel so that i can return all the three model properties in one view...
BUT :( i want to show the userName instead of userID in front of the each comment for that particular post. so i am using ICollection comments in the viewmodel so that i can return collection of the comments. and when i try to access the userName property like this #Model.Comments.User.LastName // OR Email // OR FirstName .. i am getting the compilation error. and i cant use like this because its a collection type ...
how can i retrieve the userName from the comments entity using the userID which is available in comments..
please help...
Got it all working by adding in the partial view..
_Comments Partial View..
in my partial view i have added like this...
========================
#{
ContextRepository db = new ContextRepository();
var userID = Model.UserID;
var userName = db.EUser.Find(userID).FirstName;
}
You can create a partial view to display the comment and call that inside a loop in the main view.
Post Details view
#model UserPostCommentViewModel
#{
ViewBag.Title = "Post";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#foreach (Comment comment in Model.Comments)
{
#Html.Partial("_Comment", comment);
}
_Comment partial view
#model Comment
<div class="comment">
<div class="desc">#Model.Body</div>
<div class="submitted-by">#Model.User.LastName</div>
</div>
Model issues
You need to make the navigational properties virtual to be lazy loaded.
public class Comment
{
//other properties
public virtual User User { get; set; }
public virtual Post Posts { get; set; }
}
If you are going to access these navigational properties then you need to eager load them. Otherwise you will run into Select n+1 problem. Use the Include method to eager load properties
var post = db.Posts.Include(p => Comments)
.Include(p => p.Comments.Select(c => c.User))
.Where(p => p.PostID == 1).Single();

Resources