0

I am currently working on a help desk system and writing up a view to view all tickets for a user.

A ticket consists of parent data like ticket category, open user, technician, etc. and then there is the child with ticketNotes. The first ticket note (that is added upon initial creation) is the ticket description. In the table of tickets on my view I would like to show just this one note (the ticket description) for each ticket. Here is my controller:

public ActionResult Index()
{

    var model = from t in db.Tickets
                join tn in db.TicketNotes on t.TicketId equals tn.TicketId
                where t.OpenUserId == new Guid("00000000-0000-0000-0000-000000000000")
                orderby t.OpenDate
                select t;

    return View(model);
}

My ViewModel:

namespace HelpDesk.WebUI.ViewModel
{
    public class UserTickets
    {
        public int TicketNumber { get; set; }

        public Guid CategoryId { get; set; }

        public virtual Category Category { get; set; }

        public Guid OpenUserId { get; set; }

        public virtual User OpenUser { get; set; }

        public DateTime OpenDate { get; set; }

        public Guid TechnicianId { get; set; }

        public virtual User Technician { get; set; }

        public Guid TicketStatusId { get; set; }

        public virtual TicketStatus TicketStatus { get; set; }

        public Nullable<DateTime> CloseDate { get; set; }

        public string Note { get; set; }

    }
}

My Models:

namespace HelpDesk.Model
{
    public class Ticket
    {
        public Ticket()
        {
            this.TicketNotes = new HashSet<TicketNote>();
        }
        public Guid TicketId { get; set; }

        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [Required]
        public int TicketNumber { get; set; }

        [ForeignKey("Category")]
        [Required]
        public Guid CategoryId { get; set; }

        public virtual Category Category { get; set; }

        [ForeignKey("OpenUser")]
        [Required]
        public Guid OpenUserId { get; set; }

        public virtual User OpenUser { get; set; }

        [DataType(DataType.Date)]
        [Required]
        public DateTime OpenDate { get; set; }

        [ForeignKey("Technician")]
        [Required]
        public Guid TechnicianId { get; set; }

        public virtual User Technician { get; set; }

        [ForeignKey("TicketStatus")]
        [Required]
        public Guid TicketStatusId { get; set; }

        public virtual TicketStatus TicketStatus { get; set; }

        [DataType(DataType.Date)]
        public Nullable<DateTime> CloseDate { get; set; }

        public virtual ICollection<TicketNote> TicketNotes { get; set; }
        //public virtual ICollection<TicketSubscription> TicketSubscriptions { get; set; }
    }
}

namespace HelpDesk.Model
{
    public class TicketNote
    {
        public Guid TicketNoteId { get; set; }

        [ForeignKey("Ticket")]
        [Required]
        public Guid TicketId { get; set; }

        public virtual Ticket Ticket { get; set; }

        public string Note { get; set; }
        [Display(Name = "Attachment")]
        public string AttachmentPath { get; set; }

        [MaxLength(255)]
        public string AttachmentName { get; set; }

        [ForeignKey("UserNote")]
        [Required]
        public Guid UserNoteId { get; set; }

        public virtual User UserNote { get; set; }

        [DataType(DataType.Date)]
        [Required]
        public DateTime TicketNoteDate { get; set; }

        [Display(Name = "Private Note")]
        [Required]
        public bool PublicFlag { get; set; }

        public bool Delete { get; set; }

    }
}

And here is my view:

@model IEnumerable<HelpDesk.Model.Ticket>

@{

        ViewBag.Title = "Index";
    }

    <h2>Index</h2>

    <p>
        @Html.ActionLink("Create New", "Create")
    </p>
    <table class="table">
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Category.CategoryName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.OpenUser.FullName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Technician.FullName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TicketStatus.StatusDescription)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TicketNumber)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.OpenDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.CloseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TicketNotes)
            </th>
            <th></th>
        </tr>

    @foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Category.CategoryName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.OpenUser.NTUserName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Technician.NTUserName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.TicketStatus.StatusDescription)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.TicketNumber)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.OpenDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.CloseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.TicketNotes.OrderBy(t=t.TicketId).First().TicketText)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id=item.TicketId }) |
                @Html.ActionLink("Details", "Details", new { id=item.TicketId }) |
            </td>
        </tr>
    }

    </table>

Everything works except for the ticket note which is pulling from the TicketNote Model. For that field I am getting

System.Data.Entity.DynamicProxies.Ticket_BA0BCDE55BCBE6BA2FE66FAD697C8D2C0D7AAD7C5F797406642720CB57DA2A89

As suggested by one I changed the code in my controller to be:

public ActionResult Index()
    {

        var model = db.Tickets
                    .Include(t=>t.TicketNotes)
                    .Where(t.OpenUserId == new Guid("00000000-0000-0000-0000-000000000000"))
                    .OrderBy(t => t.OpenDate);

        return View(model);
    }

and my view as suggested but I am getting an error on this line in the view:

@Html.DisplayFor(modelItem => item.TicketNotes.OrderBy(t=t.TicketId).First().TicketText)

It is saying the 'The name 't' does not exist in the current context.

djblois
  • 963
  • 1
  • 17
  • 52
  • Your Linq query is a bit pointless as you only select the ticket and not the ticket note. Those notes are pulled in later with lazy loading. – DavidG May 29 '15 at 15:43

2 Answers2

2

(optionally) Use this in your controller for better performance as it will eagerly load your TicketNotes instead of lazily load them:

public ActionResult Index()
{

    var model = db.Tickets
                  .Include(t=>t.TicketNotes)
                  .Where(t.OpenUserId == new Guid("00000000-0000-0000-0000-000000000000"))
                  .OrderBy(t=>t.OpenDate);

    return View(model);
}

And use this in your view (which will work with both eager and lazy loaded notes):

@Html.DisplayFor(modelItem => item.TicketNotes.OrderBy(t=t.TicketId).First().TicketText)
Robert McKee
  • 21,305
  • 1
  • 43
  • 57
0

It seems that you are using LazyLoading with your entity model, thus the actual type of the data is not your Ticket, but some datatype dynamically generated by EntityFramework, that handles actual loading details.

You can:

  1. Either disable the LazyLoading so that Ticket stays to be Ticket. But in such a case you will have to load all related entities manually.
  2. Or manually render desired partial views(display templates).
Community
  • 1
  • 1
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
  • I added more information to my original post. Anyone have any idea why I am getting the error? – djblois Jun 02 '15 at 16:46
  • 1
    @djblois Well, if it is not a copying mistake, then it means that you forgot an angle bracket in the lambda expression - `item.TicketNotes.OrderBy(t=t.TicketId)` shall be `item.TicketNotes.OrderBy(t => t.TicketId)`. – Eugene Podskal Jun 02 '15 at 18:07
  • Thanks that worked. sorry I am overwhelmed just learning MVC at my new job. My boss told me he was going to teach me but I am learning completely on my own. – djblois Jun 02 '15 at 19:27
  • @djblois Believe me, I understand you very well. Just be more attentive next time - that wasn't some framework idiosyncrasy but rather a minor typo. Good luck. – Eugene Podskal Jun 03 '15 at 19:31
  • Eugene I copied it from another poster above and that it was their typo. I thought it was my fault at first too. – djblois Jun 03 '15 at 19:55