Todd Penland
asked on
How to Modify Existing Controller and View to Incorporate Additional Data (from Stored Procedure)
This is a continuation of the question found at: https://www.experts-exchange.com/questions/28654179/How-to-Display-Table-of-Values-From-Stored-Procedure-in-ASP-NET-MVC5-View-Step-by-Step-Help-Needed.html
The original problem (how to get data from a stored procedure in EF Database First and display it in a view) has been solved (I think), however I now need to incorporate that solution into an already existing Controller and View.
Here's the existing Controller:
and here's the proposed solution for making my list of dates available to the View (altered to use the Details view rather than Index):
A related question that I still haven't figured out: how do I find out the name of the database context I should use in the preceding code sample? Sorry, but I'm still confused about that too. ;-)
Now for presentation: Here is my current view:
and finally, the proposed changes to the view:
I'm pretty sure once I understand how to do THIS a whole new world is going to open up ;-) Any help resolving this will be much appreciated. Thanks!
The original problem (how to get data from a stored procedure in EF Database First and display it in a view) has been solved (I think), however I now need to incorporate that solution into an already existing Controller and View.
Here's the existing Controller:
// GET: ClientGroupMembers/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ClientGroupMember clientGroupMember = db.ClientGroupMembers.Find(id);
if (clientGroupMember == null)
{
return HttpNotFound();
}
return View(clientGroupMember);
}
and here's the proposed solution for making my list of dates available to the View (altered to use the Details view rather than Index):
public ActionResult Details(int id)
{
var myintparam = new SqlParameter
{
ParameterName = "myParam",
Value = id
};
var results = context.Database.SqlQuery<DateTime>("dbo.MyStoredProcedureName @myParam").ToList();
return View(results);
}
A related question that I still haven't figured out: how do I find out the name of the database context I should use in the preceding code sample? Sorry, but I'm still confused about that too. ;-)
Now for presentation: Here is my current view:
@model Scheduler.Models.ClientGroupMember
@using Microsoft.AspNet.Identity
@Scripts.Render("~/bundles/jquery");
@{
ViewBag.Title = "Details";
}
<h2>@Model.SortName</h2>
<div>
<h4>Details</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.LastName)
</dt>
<dd>
@Html.DisplayFor(model => model.LastName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.FirstName)
</dt>
<dd>
@Html.DisplayFor(model => model.FirstName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.MidNames)
</dt>
<dd>
@Html.DisplayFor(model => model.MidNames)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Business)
</dt>
<dd>
@Html.DisplayFor(model => model.Business)
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
@Html.ActionLink("Back to List", "Index")
</p>
<div id="rootwizard">
<ul class="nav nav-pills nav-justified">
<li role="presentation" class="active"><a href="#contactinfo" data-toggle="tab" class="actve"><span class="glyphicon glyphicon-home"></span> Contact Info</a></li>
<li role="presentation"><a href="#schedules" data-toggle="tab"><span class="glyphicon glyphicon-apple"></span> Schedules</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="contactinfo">
<div class="row">
<p>Coming soon...</p>
</div>
</div>
<div class="tab-pane" id="schedules">
<div class="row">
CODE TO DISPLAY COLUMN HEADING GOES HERE
</div>
<div>
CODE TO DISPLAY LIST OF DATES GOES HERE
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$('#rootwizard').bootstrapWizard({ 'tabClass': 'nav nav-pills' });
});
</script>
and finally, the proposed changes to the view:
@model IEnumerable<DateTime>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<table>
@foreach(var date in model)
{
<tr>
<td>@date</td>
</tr>
}
</table>
I'm pretty sure once I understand how to do THIS a whole new world is going to open up ;-) Any help resolving this will be much appreciated. Thanks!
ASKER
Sure thing. Here's the model:
public partial class ClientGroupMember
{
public ClientGroupMember()
{
this.ClientGroupMemberAddresses = new HashSet<ClientGroupMemberAddress>();
this.ClientGroupMemberEmails = new HashSet<ClientGroupMemberEmail>();
this.ClientGroupMemberPhones = new HashSet<ClientGroupMemberPhone>();
this.ClientGroupMembersDatesNotAvailables = new HashSet<ClientGroupMembersDatesNotAvailable>();
this.Schedules = new HashSet<Schedule>();
}
public int Id { get; set; }
public int GroupID { get; set; }
public Nullable<int> Title { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string MidNames { get; set; }
[NotMapped]
[Display(Name = "Sort Name")]
public string SortName
{
get { return LastName + ", " + FirstName + " " + MidNames; }
}
public Nullable<int> Suffix { get; set; }
public string Business { get; set; }
public System.DateTime DateCreated { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> StartDate { get; set; }
public Nullable<System.DateTime> DueDate { get; set; }
public Nullable<System.DateTime> InactiveDate { get; set; }
public Nullable<bool> Unavailable { get; set; }
public Nullable<bool> Assigned { get; set; }
public Nullable<int> SinceLastTeamed { get; set; }
public Nullable<int> SinceLastWildcard { get; set; }
public Nullable<int> LegacyID { get; set; }
public virtual ICollection<ClientGroupMemberAddress> ClientGroupMemberAddresses { get; set; }
public virtual ICollection<ClientGroupMemberEmail> ClientGroupMemberEmails { get; set; }
public virtual ICollection<ClientGroupMemberPhone> ClientGroupMemberPhones { get; set; }
public virtual ClientGroup ClientGroup { get; set; }
public virtual NameSuffix NameSuffix { get; set; }
public virtual Title Title1 { get; set; }
public virtual ICollection<ClientGroupMembersDatesNotAvailable> ClientGroupMembersDatesNotAvailables { get; set; }
public virtual ICollection<Schedule> Schedules { get; set; }
}
And which is the property that should hold the results of the SP? Is there such a property? Is it the Schedules ?
ASKER
Now we're into parts of EF that I don't fully understand yet but I'll try to answer as best I can.
This line represents the one to many relationship in the database between the ClientGroupMembers table and the Schedule table. Here is the model for Schedule (if that helps):
(Participant in this model is the foreign key "Id" from ClientGroupMembers.)
Does this help?
This line represents the one to many relationship in the database between the ClientGroupMembers table and the Schedule table. Here is the model for Schedule (if that helps):
public partial class Schedule
{
public int Id { get; set; }
public System.DateTime IntervalStartDate { get; set; }
public int TeamNumber { get; set; }
public int Participant { get; set; }
public virtual ClientGroupMember ClientGroupMember { get; set; }
}
(Participant in this model is the foreign key "Id" from ClientGroupMembers.)
Does this help?
Yes but i think you would not need the SP part. EF should have this filled already. I have to go out be back with suggestions in a while.
Ok,
First of all i think that the Schedules are already there due to EF lazy loading. So i would suggest to first take the following steps that will be the less intrusive to what you currently have.
In that folder add a new item (cshtml) named "Schedules.cshtml"
In that View add the following code:
You will use that in your main View.
Lets try this. I can see that there may be some issues but i would like you to first try this and if it does not work i will give further instructions. The issue you might have is an exception saying that :
but judging from your controller's code, you may not experience that.
Giannis
First of all i think that the Schedules are already there due to EF lazy loading. So i would suggest to first take the following steps that will be the less intrusive to what you currently have.
1. Create a template.
Browse to your \Views\Shared folder and create a new Folder named "DisplayTemplates".In that folder add a new item (cshtml) named "Schedules.cshtml"
In that View add the following code:
@model IEnumerable<Schedule>
@foreach(var schedule in Model)
{
<div class="row">
@schedule.IntervalStartDate
</div>
}
You will use that in your main View.
2. Use the template.
In your View as it is defined now you will need to change the following part (lines 67 to 69): <div>
CODE TO DISPLAY LIST OF DATES GOES HERE
</div>
to :@Html.DisplayFor(m=>m.Schedules,"Schedules")
Lets try this. I can see that there may be some issues but i would like you to first try this and if it does not work i will give further instructions. The issue you might have is an exception saying that :
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
but judging from your controller's code, you may not experience that.
Giannis
ASKER
Done. I got an entirely different result though. This is what is displayed in my view where the list of dates should be:
System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12
Lets go a step further then.
In your controller change the following line:
to:
Giannis
In your controller change the following line:
ClientGroupMember clientGroupMember = db.ClientGroupMembers.Find(id);
to:
ClientGroupMember clientGroupMember = db.ClientGroupMembers.Include("Schedules").Where(x=> x.Id == id).FirstOrDefault();
Giannis
ASKER
Done. That produces this exception though:
Error 1 Cannot implicitly convert type 'System.Linq.IQueryable<Sc heduler.Mo dels.Clien tGroupMemb er>' to 'Scheduler.Models.ClientGr oupMember' . An explicit conversion exists (are you missing a cast?) projectPath\ClientGroupMem bersContro ller.cs 33 51 Scheduler
Error 1 Cannot implicitly convert type 'System.Linq.IQueryable<Sc
yes i noticed that a bit late and updated my post. Can you add the FirstOrDefault() ?
ASKER
Yes. I added it. (I have to admit that, at this point I'm just following your lead...not really sure what I'm doing exactly.)
Changed the line in the controller to:
When I view the page I'm still getting this result though:
I should have pointed out that I had to slightly change the model directive in the shared view from:
@model IEnumerable<Schedule>
to:
@model IEnumerable<Scheduler.Mode ls.Schedul e>
I doubt that makes any difference but wanted to point it out just in case.
Changed the line in the controller to:
ClientGroupMember clientGroupMember = db.ClientGroupMembers.Include("Schedules").Where(x => x.Id == id).FirstOrDefault();
When I view the page I'm still getting this result though:
System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12
I should have pointed out that I had to slightly change the model directive in the shared view from:
@model IEnumerable<Schedule>
to:
@model IEnumerable<Scheduler.Mode
I doubt that makes any difference but wanted to point it out just in case.
No, it is ok what you did. I am not on a pc to do any test so lets try two things:
1. Change IEnumerable to IQueryable.
If that does not work :
2. Add ToList() on the DisplayFor as
Hopefully this will help it to enumerate the values.
Just as info, dynamic proxy is the way of EF to enumerate dependencies. You select from a table and EF will use DynamicProxy to lazy load related tables (like Schedules in our case).
Giannis
1. Change IEnumerable to IQueryable.
If that does not work :
2. Add ToList() on the DisplayFor as
@Html.DisplayFor(m=>m.Schedules.ToList(),"Schedules")
Hopefully this will help it to enumerate the values.
Just as info, dynamic proxy is the way of EF to enumerate dependencies. You select from a table and EF will use DynamicProxy to lazy load related tables (like Schedules in our case).
Giannis
ASKER
I changed IEnumerable to IQueryable but got exactly the same result. I changed it back to IEnumerable and added ToList() to the view. When I ran it I got this exception:
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
Source=System.Web.Mvc
StackTrace:
at System.Web.Mvc.ModelMetadata.FromLambdaExpression[TParameter,TValue](Expression`1 expression, ViewDataDictionary`1 viewData, ModelMetadataProvider metadataProvider)
at System.Web.Mvc.ModelMetadata.FromLambdaExpression[TParameter,TValue](Expression`1 expression, ViewDataDictionary`1 viewData)
at System.Web.Mvc.Html.TemplateHelpers.TemplateFor[TContainer,TValue](HtmlHelper`1 html, Expression`1 expression, String templateName, String htmlFieldName, DataBoundControlMode mode, Object additionalViewData, TemplateHelperDelegate templateHelper)
at System.Web.Mvc.Html.TemplateHelpers.TemplateFor[TContainer,TValue](HtmlHelper`1 html, Expression`1 expression, String templateName, String htmlFieldName, DataBoundControlMode mode, Object additionalViewData)
at System.Web.Mvc.Html.DisplayExtensions.DisplayFor[TModel,TValue](HtmlHelper`1 html, Expression`1 expression, String templateName)
at ASP._Page_Views_ClientGroupMembers_Details_cshtml.Execute() in c:\Users\MichaelTodd\Documents\Visual Studio 2013\Projects\Scheduler\Scheduler\Views\ClientGroupMembers\Details.cshtml:line 69
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
at System.Web.WebPages.StartPage.RunPage()
at System.Web.WebPages.StartPage.ExecutePageHierarchy()
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
InnerException:
ASKER
Here's where we are now by the way (for anyone else who may be following this later):
Controller:
Shared View:
View:
Controller:
// GET: ClientGroupMembers/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ClientGroupMember clientGroupMember = db.ClientGroupMembers.Include("Schedules").Where(x => x.Id == id).FirstOrDefault();
if (clientGroupMember == null)
{
return HttpNotFound();
}
return View(clientGroupMember);
}
Shared View:
@model IEnumerable<Scheduler.Models.Schedule>
@foreach (var schedule in Model)
{
<div class="row">
@schedule.IntervalStartDate
</div>
}
View:
@model Scheduler.Models.ClientGroupMember
@using Microsoft.AspNet.Identity
@Scripts.Render("~/bundles/jquery");
@{
ViewBag.Title = "Details";
}
<h2>@Model.SortName</h2>
<div>
<h4>Details</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.LastName)
</dt>
<dd>
@Html.DisplayFor(model => model.LastName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.FirstName)
</dt>
<dd>
@Html.DisplayFor(model => model.FirstName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.MidNames)
</dt>
<dd>
@Html.DisplayFor(model => model.MidNames)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Business)
</dt>
<dd>
@Html.DisplayFor(model => model.Business)
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
@Html.ActionLink("Back to List", "Index")
</p>
<div id="rootwizard">
<ul class="nav nav-pills nav-justified">
<li role="presentation" class="active"><a href="#contactinfo" data-toggle="tab" class="actve"><span class="glyphicon glyphicon-home"></span> Contact Info</a></li>
<li role="presentation"><a href="#schedules" data-toggle="tab"><span class="glyphicon glyphicon-apple"></span> Schedules</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="contactinfo">
<div class="row">
<p>Coming soon...</p>
</div>
</div>
<div class="tab-pane" id="schedules">
<div class="row">
<div><strong>Schedule</strong></div>
<hr />
</div>
<div>
@Html.DisplayFor(m => m.Schedules.ToList(), "Schedules")
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$('#rootwizard').bootstrapWizard({ 'tabClass': 'nav nav-pills' });
});
</script>
Hmm, can we try something else?
Rename the template to "Schedule" ( remove the last s)
Change the model to Schedule instead of IEnumerable<Schedule>.
Change the DisplayFor as
@Html.DisplayFor(m=>m.Sche dules)
Sorry but i am not on a pc to actually test.
Giannis
Rename the template to "Schedule" ( remove the last s)
Change the model to Schedule instead of IEnumerable<Schedule>.
Change the DisplayFor as
@Html.DisplayFor(m=>m.Sche
Sorry but i am not on a pc to actually test.
Giannis
ASKER
No worries...I'm just grateful for the help! ;-)
These changes produced the same result we got earlier:
Controller (no change from before)
Shared View (renamed Schedule.cshtml from Schedules.cshtml):
View:
These changes produced the same result we got earlier:
System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12
Controller (no change from before)
Shared View (renamed Schedule.cshtml from Schedules.cshtml):
@model Scheduler.Models.Schedule
@foreach (var schedule in Model)
{
<div class="row">
@schedule.IntervalStartDate
</div>
}
View:
@model Scheduler.Models.ClientGroupMember
@using Microsoft.AspNet.Identity
@Scripts.Render("~/bundles/jquery");
@{
ViewBag.Title = "Details";
}
<h2>@Model.SortName</h2>
<div>
<h4>Details</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.LastName)
</dt>
<dd>
@Html.DisplayFor(model => model.LastName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.FirstName)
</dt>
<dd>
@Html.DisplayFor(model => model.FirstName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.MidNames)
</dt>
<dd>
@Html.DisplayFor(model => model.MidNames)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Business)
</dt>
<dd>
@Html.DisplayFor(model => model.Business)
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
@Html.ActionLink("Back to List", "Index")
</p>
<div id="rootwizard">
<ul class="nav nav-pills nav-justified">
<li role="presentation" class="active"><a href="#contactinfo" data-toggle="tab" class="actve"><span class="glyphicon glyphicon-home"></span> Contact Info</a></li>
<li role="presentation"><a href="#schedules" data-toggle="tab"><span class="glyphicon glyphicon-apple"></span> Schedules</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="contactinfo">
<div class="row">
<p>Coming soon...</p>
</div>
</div>
<div class="tab-pane" id="schedules">
<div class="row">
<div><strong>Schedule</strong></div>
<hr />
</div>
<div>
@Html.DisplayFor(m => m.Schedules)
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$('#rootwizard').bootstrapWizard({ 'tabClass': 'nav nav-pills' });
});
</script>
Also this change to the template
@model Scheduler.Models.Schedule
<div class="row">
@Model.IntervalStartDate
</div>
ASKER
Done. Same result though:
System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12System.Data.Entity.DynamicProxies.ClientGroupMember_1CE87C82519B5BC54E8BB9142812F0A78322A167CB434675C6A862954D88CF12
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
To be honest i knew it would, but i really wanted the template to work, as it feels more MVC appropriate. And more reusable.
Maybe tomorrow i will create a little project to see where i was wrong...
Glad i could help.
Giannis
Maybe tomorrow i will create a little project to see where i was wrong...
Glad i could help.
Giannis
ASKER
Can't tell you how much I appreciate the help with this. If you do find the more MVC appropriate and reusable solution I'd love to see that too. Thank you!!!
You just made me an ASP.NET Guru, so that's the list i can do.... ;-)
ASKER
WINNING!!! :-D
Ok, i couldn't wait, so i created a project from scratch. I only referenced a dll which handles my database models etc.
I have a model called "villas" and each villa has a collection of Photos, as your ClientGroupMembers model has a collection of schedules. I followed the following steps exactly (from the standard MVC template in VS 2013):
"Data" in the controller is my dll that handles the database, but that doesn't make any difference.
The result is the following:
As you can see as defined on the view, there is the description and also a list of strings defining the Photos.
As i said it should have worked. And this way i could reuse that template to other places.
Do you see any difference with what you had?
Giannis
I have a model called "villas" and each villa has a collection of Photos, as your ClientGroupMembers model has a collection of schedules. I followed the following steps exactly (from the standard MVC template in VS 2013):
1. I added a folder DisplayTemplates under \Views\Shared.
2. Added the following code:
@model MyNamespace.Photos
<tr><td>@Model.Image</td></tr>
3. Changed the \Views\Home\Index.cshtml
@model MyNamespace.villas
@Model.property_description
<table>
@Html.DisplayFor(m => m.Photos)
</table>
4. Modified HomeController
public ActionResult Index()
{
using(Data data = new Data())
{
var model = data.villas.Include("Photos").Where(x => x.ID == 17050).FirstOrDefault();
return View(model);
}
}
"Data" in the controller is my dll that handles the database, but that doesn't make any difference.
The result is the following:
As you can see as defined on the view, there is the description and also a list of strings defining the Photos.
As i said it should have worked. And this way i could reuse that template to other places.
Do you see any difference with what you had?
Giannis
ASKER
@model Scheduler.Models.Schedule
@Model.IntervalStartDate<br />
I've adapted your solution to mine and it's working perfectly with one exception: the column name for the schedule dates. In your example you are using this as the column name (I think):
@Model.property_descriptio
However I can't figure out how to change that so that it will read the Display Name I've given this column in my model:
[Display(Name="Schedule Date")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
public System.DateTime IntervalStartDate { get; set; }
(remember that IntervalStartDate is in a different model (Schedule) than the one the rest of the page is derived from (ClientGroupMember)).In my View I entered this:
<div class="tab-pane" id="schedules">
<div class="row">
<div><strong>@Html.DisplayNameFor(m => m.Schedules)</strong></div>
<hr />
</div>
<div>
@Html.DisplayFor(m => m.Schedules)
</div>
</div>
Instead of getting the column name "Schedule Date" (from the model), I'm getting the name of the model "Schedule". I also notice that the date format I specified in the model's annotations is not being applied:
Any idea what I'm doing wrong?
Hi,
Good to know it finally worked.
I think you need to use @Html.LabelFor.
In my example i just added another property of my model. Property_description is a field in my table.
In order to apply the format you need to go to your template and use @Html.DisplayFor(m=>m.Inte rvalStartD ate)
This will cause it to get the declared format.
Giannis
Good to know it finally worked.
I think you need to use @Html.LabelFor.
In my example i just added another property of my model. Property_description is a field in my table.
In order to apply the format you need to go to your template and use @Html.DisplayFor(m=>m.Inte
This will cause it to get the declared format.
Giannis
Sorry, you also need to apply @Html.DisplayName on your template instead of the main view.
ASKER
Thank you again. I think I'm just about there. I moved everything from the view to the view template:
so that the view now looks like this:
That does the trick as far as the Display Name is concerned, however as you can see it now repeats with every entry (not the desired outcome) rather than just appearing once at the top of the column:
@model Scheduler.Models.Schedule
<div class="row">
<div><strong>@Html.DisplayNameFor(m => m.IntervalStartDate)</strong></div>
<hr />
</div>
<div>
<a href="..\..\Schedules\Details\@Model.TeamNumber\@Model.IntervalStartDate">@Model.IntervalStartDate</a><br />
</div>
so that the view now looks like this:
<div class="tab-pane" id="schedules">
@Html.DisplayFor(m => m.Schedules)
</div>
That does the trick as far as the Display Name is concerned, however as you can see it now repeats with every entry (not the desired outcome) rather than just appearing once at the top of the column:
It is supposed to be that way. Remember that your template is for a single object and not for a collection or similar. So, DisplayFor will apply that template for every item in the collection. If you add the header in the template, it will be applied to each item.
I would have the DisplayName in the main view. But since in the main view you are dealing with the collection i would also add the attribute on the collection.
So, in the Schedule model, instead of:
One thing i do not know is if it can go to the EF model.. I think not because it is autogenerated. I usually create my own derived classes for the Models in mvc.
I am not sure if what i said helps at all...
Giannis
I would have the DisplayName in the main view. But since in the main view you are dealing with the collection i would also add the attribute on the collection.
So, in the Schedule model, instead of:
[Display(Name="Schedule Date")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
public System.DateTime IntervalStartDate { get; set; }
i would just have the Format and then in the ClientGroupMembers model i would add to the Schedules property: [Display(Name="Schedule Dates")]
public ICollection<Schedule> Schedules{ get; set; }
One thing i do not know is if it can go to the EF model.. I think not because it is autogenerated. I usually create my own derived classes for the Models in mvc.
I am not sure if what i said helps at all...
Giannis
ASKER
Success!!!
I do have a derived class (in Metadata.cs) for each of my models so that my annotations aren't overwritten during database updates, so I was able to put the suggested annotation there. It worked perfectly.
So here's what I ended up with (just in case it might help someone else with a similar problem):
ClientGroupMembers Model (Derived)
Controller
View Template
View
I wish I could give you another bunch of points for the extra help on this! Thank you very much!!!
I do have a derived class (in Metadata.cs) for each of my models so that my annotations aren't overwritten during database updates, so I was able to put the suggested annotation there. It worked perfectly.
So here's what I ended up with (just in case it might help someone else with a similar problem):
ClientGroupMembers Model (Derived)
[Display(Name = "Schedule Date")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
public ICollection<Schedule> Schedules { get; set; }
Controller
// GET: ClientGroupMembers/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Session["_SessionGroupMember"] = id;
ClientGroupMember clientGroupMember = db.ClientGroupMembers.Include("Schedules").Where(x => x.Id == id).FirstOrDefault();
if (clientGroupMember == null)
{
return HttpNotFound();
}
return View(clientGroupMember);
}
View Template
@model Scheduler.Models.Schedule
<a href="..\..\Schedules\Details\@Model.TeamNumber\@Model.IntervalStartDate">@Html.DisplayFor(m => m.IntervalStartDate)</a><br />
View
<div class="tab-pane" id="schedules">
<div class="row">
<div><strong>@Html.DisplayNameFor(m => m.Schedules)</strong></div>
<hr />
</div>
<div>
@Html.DisplayFor(m => m.Schedules)
</div>
</div>
I wish I could give you another bunch of points for the extra help on this! Thank you very much!!!
I will gladly help you out with this one, but i would need a look at your model structure. Can you show how is Scheduler.Models.ClientGro
Giannis