0

I am creating a sample app using angularjs, entity framework code-first, and webapi. I am running into an issue when binding data. I have a view with a HTML table that displays a list of "court" entities. There is also a district entity that has a one-to-many relationship to the courts (districts on the "one" side) represented by navigation properties in my models. What is happeneing is the web api controller is returning all the data but by the time it gets to the angular controller most of the results, not all, end up as "undefined".

enter image description here

Web api controller:

[HttpGet]
[Route("api/court/search/district/{DistrictId}/")]
public HttpResponseMessage GetCourtsByDistrict(string DistrictId)
{
    DistrictId = DistrictId == "0" ? null : DistrictId;
    HttpResponseMessage response = null;
    IEnumerable<Court> courts;

    courts = courtService.FindBy(d => d.DistrictId.Contains(DistrictId));
    response = Request.CreateResponse(HttpStatusCode.OK, courts);

    return response;
}

Court Service Find By method:

public IEnumerable<Court> FindBy(Expression<Func<Court, bool>> predicate)
{
    IEnumerable<Court> query = CourtRepository.FindBy(predicate);
    return query;
}

Angular factory:

factory.getCourtsByDistrict = function (districtId) {
    url = baseAddress + "court/search/district/" + districtId;
    return $http.get(url);
};

Angular controller:

$scope.getCourtsByDistrict = function (DistrictID) {
    courtFactory.getCourtsByDistrict(DistrictID)
        .success(function (data) {
            $scope.courts = data;
        })
        .error(function (error) {
            alertService.add('danger', 'Unable to load district data: ' + JSON.stringify(error));
        });
};

Models: public partial class Court { public Court() { Employees = new HashSet(); }

    [Key]
    public string CourtId { get; set; }
    public string CourtName { get; set; }
    public string DistrictId { get; set; }
    public virtual District District { get; set; }

    [ForeignKey("CourtId")]
    public ICollection<Employee> Employees { get; set; }
}

public partial class District
{
    public District()
    {
        Courts = new HashSet<Court>();
        Employees = new HashSet<Employee>();
    }

    [Key]
    public string DistrictId { get; set; }
    public string DistrictName { get; set; }

    [ForeignKey("DistrictId")]
    public virtual ICollection<Court> Courts { get; set; }

    [ForeignKey("DistrictId")]
    public ICollection<Employee> Employees { get; set; }
}

If I remove the following line from the Court model or remove the virtual property:

public virtual District District { get; set; }

then all the court entity data returns correctly. However, I want to return the district name property from the district entity also, for each court in the view's table, so I kind of need the virtual district property. I am not sure what is happening. There is also an employee entity which is on the one side of a one to many with both the district and courts entity. It is almost like angularJS cannot handle the level of relationshsips the nav properties are creating.

I looked further into the issue with fiddler and if you look at the image below you can see adding the (virtual) navigation property to my class changes the structure of the JSON returned by the web api controller, which seems to be producing the "undefined" items:

enter image description here

steveareeno
  • 1,925
  • 5
  • 39
  • 59

1 Answers1

1

Ok, the virtual keyword when omitted will prevent EF from loading that data into your collection. In that case, if you really want the data to be loaded, you must tell it to EF, more or less like this:

var query = Db.District.Include(f => f.Courts) //this will populate the Courts collection for you in the case your property is not virtual 

Check Scott's answer here

Also, maybe you should create a DTO to send data back to the client the way you want, that is also a good practice to model the data you want to send instead of sending the entire graph of the object, this will work like a ViewModel.

Community
  • 1
  • 1
Bruno Casarotti
  • 623
  • 8
  • 23
  • Thanks Bruno. I thought about doing a viewmodel. I currently do that with all my MVC apps. It would require me to restructure my app but if that is the case, so be it. I will also look into the .Include statement. Thanks. – steveareeno Dec 01 '15 at 19:05
  • There is a "simple" way to do it, do you know AutoMapper, it is very easy to implement: [take a look here](https://github.com/AutoMapper/AutoMapper/wiki/Getting-started) – Bruno Casarotti Dec 01 '15 at 19:13
  • I have used Omu.ValueInjecter for injecting my models into viewmodels. I will look at automapper also. Thank. – steveareeno Dec 01 '15 at 19:27
  • Ran into one issue. Since I am using a repositories, IEnumerables, and services, .Include is not available to me. I add a sample service method to my original post – steveareeno Dec 01 '15 at 19:56
  • You must use the Include method inside your implementation of FindBy of the current repository and everything will work as expected – Bruno Casarotti Dec 01 '15 at 20:00
  • I was able to get my repository working with the .Include method but the problem persists, though not as bad. I think I am having an issue with circular references in my JSON. I have read a lot about this but haven't found any solution that fixes the problem for me. The issue is happening whether I use eager or lazy loading. – steveareeno Dec 02 '15 at 01:44
  • Yes, probably. I think that leads you to another question here in the Stack Overflow. Although check this link for the answer http://stackoverflow.com/questions/30769870/web-api-json-serializing-circular-references – Bruno Casarotti Dec 02 '15 at 02:27
  • The suggestion in that post worked, setting ReferenceLoopHandling to ignore. However, I think I am going back to your original recommendation and creating viewmodels. I can flatten out the json in my webapi controller with the view model and not have to mess with any of my navigation properties. Thanks for all the help – steveareeno Dec 02 '15 at 11:07
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/96803/discussion-between-bruno-grisolia-casarotti-and-steveareeno). – Bruno Casarotti Dec 02 '15 at 13:03