2
votes

I'm a newbie to web development, C# and .net (VS2013), not sure I'm asking this correctly but after searching through books, all through the telerik docs, and google searches I'm still stuck on something simple.

What I'm trying to do is create a page in an MVC app using the Kendo Grid and Ajax to display information on client locations and include the primary phone.number and primary address.add1, coming from different DB tables, in the grid.

My Domain Objects

public partial class location
{
    public location()
    {
        this.addresses = new HashSet<address>();
        this.location_note = new HashSet<location_note>();
        this.phones = new HashSet<phone>();
    }
    public long id { get; set; }
    public long acct_id { get; set; }
    public Nullable<bool> active { get; set; }
    public string name { get; set; }
    public string contact { get; set; }
    public Nullable<long> location_account_id { get; set; }

    public virtual ICollection<address> addresses { get; set; }
    public virtual ICollection<location_note> location_note { get; set; }
    public virtual ICollection<phone> phones { get; set; }
}

public partial class address
{
    public long id { get; set; }
    public long acct_id { get; set; }
    public long location_id { get; set; }
    public bool primary { get; set; }
    public string add1 { get; set; }
    public string add2 { get; set; }
    public string city { get; set; }
    public string county { get; set; }
    public string state { get; set; }
    public string zip { get; set; }
    public string comment { get; set; }
    public long address_type_id { get; set; }

    public virtual address_type address_type { get; set; }
    public virtual location location { get; set; }
}

public partial class phone
{
    public long id { get; set; }
    public long acct_id { get; set; }
    public long location_id { get; set; }
    public bool primary { get; set; }
    public long phone_type_id { get; set; }
    public string number { get; set; }

    public virtual location location { get; set; }
    public virtual phone_type phone_type { get; set; }

My Scaffolded LocationController

public class LocationController : Controller
{
    private vessenceEntities db = new vessenceEntities();

    public ActionResult Index()
    {
        return View();
    }

    public ActionResult locations_Read([DataSourceRequest]DataSourceRequest request)
    {
        IQueryable<location> locations = db.locations;
        DataSourceResult result = locations.ToDataSourceResult(request, location => new {
            id = location.id,
            acct_id = location.acct_id,
            active = location.active,
            name = location.name,
            contact = location.contact,
            location_account_id = location.location_account_id,
        });

        return Json(result);
    }

My View - Index.cshtml

@(Html.Kendo().Grid<VEPrototype.location>()
  .Name("grid")
  .Columns(columns =>
  {
    columns.Bound(c => c.acct_id);
    columns.Bound(c => c.active);
    columns.Bound(c => c.name);
    columns.Bound(c => c.contact);
    columns.Bound(c => c.location_account_id);
    })
  })
  .ToolBar(toolbar => {
        toolbar.Create();
        toolbar.Excel();
        toolbar.Pdf();
  }) 
  .Editable(editable => editable.Mode(GridEditMode.PopUp))
  .Pageable()
  .Sortable(sortable => {
      sortable.SortMode(GridSortMode.MultipleColumn);
  })
  .Filterable()
  .Scrollable()
  .DataSource(dataSource => dataSource
      .Ajax()
      .Model(model => model.Id(p => p.id))
      .Read(read => read.Action("locations_Read", "Location"))
  )

Things I have tried to do:

  1. When I do a debug stop in the LocationController I can't see any data in the IQueryable location variable, just queries - but if I do a ToList() then I can see the correct addresses in each location. So I've tried adding values to the json result going to the view like:

    primaryaddress = location.addresses.GetElementAt(0).add1
    

    Just to see if I could get something back - doesn't work. Seems like even if I add the extra address and phone data to the Json result the view is tied to the location model so I can't get to those extra data pieces I've added, makes sense. So do I need to associate the view to a different model that I would build somewhere else and add the Location, Address, and Phone data I want in the grid?

  2. I've tried creating another location partial class with PrimaryAddress and PrimaryPhone properties and within that class doing a foreach through the addresses in the location class - but when the getters run the address hasn't been populated yet and I get null reference exceptions.

When using the standard razor syntax and the VS scaffolded controller I can see the entire location domain object in the view and for each through the addresses of each location and find the primary address and phone. I'm tripping up when using the Kendo Grid with Ajax where its passing Json to the view and I'm lost on how to get the addresses and phone data into the view. Sorry this is probably basic, if someone could point me to some documentation on best practices for using the Kendo controls it might help me get unstuck. I have searched and looked through the telerik website but the Ajax/Json examples I've found are pulling data from only one table in a DB which works great with the scaffolded components already.

Thanks in advance...

1

1 Answers

0
votes

I don't have time for a full answer here but a few things off the top... IQueryable is a deferred execution interface, meaning that the query is not actually run until you call something like .ToList() on the query, see here. Secondly I would recommend looking into possibly using AutoMapper so that you can separate your data transfer objects(client models) from those being persisted to the database(entity models)(you can also do this mapping without Automapper if the mapping are simple). Taking both of these things into account will allow you to test the DTO and client bindings in one context and test the controller through to entity bindings in another context, thereby removing some of the magic.

EDIT #1:

Here is an example of Entity to DTO Mapping using OData:

    [EnableQuery]
    public IQueryable<FooDto> Get()
    {
        // Load set into read-only context for performance.
        var sets = Context.Foos.AsNoTracking();
        // AutoMapper will modify the database query to support exposing DTOs
        var setsDtos = sets.Project().To<FooDto>();
        return setsDtos;
    }

Or here is a case for a single result using OData:

    [EnableQuery]
    public SingleResult<FooDto> Get(string key)
    {
        return
            SingleResult.Create(
                Context.Foos.AsNoTracking().Where(set => set.FooId == key)
                    .Project()
                    .To<FooDto>()
                    .AsQueryable());
    }