0
votes

I'm using Knockout.js 2.2.1 and Breeze 1.3.5 to retrieve and display some data but the results are way off. The data comes from a self referencing table. As far as I can tell Knockout seems to think that the Children property of each item should return the entire array and not the actual children of item. What am I doing wrong?

UPDATE 1: I created a fiddle and I get the expected results but it doesn't use breeze.js. So perhaps this is a breeze.js issue? Something of note in the fiddle is that Children and Name are both referenced without parenthesis whereas in my full blown application breeze.js seems to be converting them to the proper observables* and requiring parenthesis for the Name.

Current result:

Apparel
- Apparel
Art
- Art
Books
- Books
Movies
- Movies
test
- test
Blu-ray
- Blu-ray
DVD
- DVD
Animation
- Animation
Accessories
- Accessories

Expected result:

Apparel
- Accessories
Art
- Animation
Books
Movies
- Blu-ray
- DVD
test

VM:

var vm = {
    categories: ko.observableArray()
};

Knockout.js markup:

<div data-bind="foreach: categories">
    <div data-bind="text: Name"></div>
    <div data-bind="foreach: Children">
        <div data-bind="text: ' - ' + Name()"></div>
    </div>
</div>

Breeze code:

var query = breeze.EntityQuery.from("Category")
    .orderBy("ParentCategoryId, Name")
    .expand("Children");

_entityManager
    .executeQuery(query)
    .then(function (data) {
        vm.categories.removeAll();
        console.log("here: " + data.results.length); -- produces 9
        data.results.forEach(function (item) {
            vm.categories.push(item);
        });
    })
    .fail(function (error) { console.log("Error: " + error); });

Breeze query results:

[ { "$id" : "1",
    "$type" : "SR.Data.Models.Domain.Category, SR.Data",
    "CategoryId" : 5,
    "Children" : [ { "$id" : "2",
          "$type" : "SR.Data.Models.Domain.Category, SR.Data",
          "CategoryId" : 6,
          "Children" : [  ],
          "CreatedOn" : "2013-05-31T11:29:11.860",
          "Description" : "Accessories",
          "IsDeleted" : false,
          "IsPublished" : true,
          "Name" : "Accessories",
          "ParentCategory" : { "$ref" : "1" },
          "ParentCategoryId" : 5
        } ],
    "CreatedOn" : "2013-05-31T11:28:37.677",
    "Description" : "Apperal",
    "IsDeleted" : false,
    "IsPublished" : true,
    "Name" : "Apparel"
  },
  { "$id" : "3",
    "$type" : "SR.Data.Models.Domain.Category, SR.Data",
    "CategoryId" : 3,
    "Children" : [ { "$id" : "4",
          "$type" : "SR.Data.Models.Domain.Category, SR.Data",
          "CategoryId" : 4,
          "Children" : [  ],
          "CreatedOn" : "2013-05-31T11:25:46.333",
          "Description" : "Animation",
          "IsDeleted" : false,
          "IsPublished" : true,
          "Name" : "Animation",
          "ParentCategory" : { "$ref" : "3" },
          "ParentCategoryId" : 3
        } ],
    "CreatedOn" : "2013-05-31T11:25:30.250",
    "Description" : "Art",
    "IsDeleted" : false,
    "IsPublished" : true,
    "Name" : "Art"
  },
  { "$id" : "5",
    "$type" : "SR.Data.Models.Domain.Category, SR.Data",
    "CategoryId" : 1,
    "Children" : [  ],
    "CreatedOn" : "2013-05-13T17:14:15.880",
    "Description" : "Books",
    "IsDeleted" : false,
    "IsPublished" : true,
    "Name" : "Books"
  },
  { "$id" : "6",
    "$type" : "SR.Data.Models.Domain.Category, SR.Data",
    "CategoryId" : 2,
    "Children" : [ { "$id" : "7",
          "$type" : "SR.Data.Models.Domain.Category, SR.Data",
          "CategoryId" : 7,
          "Children" : [  ],
          "CreatedOn" : "2013-05-31T11:31:05.710",
          "Description" : "Blu-ray",
          "IsDeleted" : false,
          "IsPublished" : true,
          "Name" : "Blu-ray",
          "ParentCategory" : { "$ref" : "6" },
          "ParentCategoryId" : 2
        },
        { "$id" : "8",
          "$type" : "SR.Data.Models.Domain.Category, SR.Data",
          "CategoryId" : 8,
          "Children" : [  ],
          "CreatedOn" : "2013-05-31T11:31:15.000",
          "Description" : "DVD",
          "IsDeleted" : false,
          "IsPublished" : true,
          "Name" : "DVD",
          "ParentCategory" : { "$ref" : "6" },
          "ParentCategoryId" : 2
        }
      ],
    "CreatedOn" : "2013-05-14T12:13:36.570",
    "Description" : "DVD's & Blu-ray",
    "IsDeleted" : false,
    "IsPublished" : true,
    "Name" : "Movies"
  },
  { "$id" : "9",
    "$type" : "SR.Data.Models.Domain.Category, SR.Data",
    "CategoryId" : 11,
    "Children" : [  ],
    "CreatedOn" : "2013-06-03T15:32:50.023",
    "Description" : "test",
    "IsDeleted" : false,
    "IsPublished" : true,
    "Name" : "test"
  },
  { "$ref" : "7" },
  { "$ref" : "8" },
  { "$ref" : "4" },
  { "$ref" : "2" }
]

Category entity:

public class Category
{
    public Category() { }

    public virtual int CategoryId { get; set; }

    public virtual int? ParentCategoryId { get; set; }

    public virtual int? PictureId { get; set; }

    public virtual string Name { get; set; }

    public virtual string Description { get; set; }

    public virtual bool IsPublished { get; set; }

    public virtual bool IsDeleted { get; set; }

    public virtual DateTime CreatedOn { get; set; }

    public virtual Category ParentCategory { get; set; }

    public virtual Picture Picture { get; set; }

    public virtual ICollection<Category> Children { get; set; }
}

Category mapping:

modelBuilder.Entity<Category>().HasKey(a => a.CategoryId);
modelBuilder.Entity<Category>().HasOptional(x => x.Picture).WithMany().HasForeignKey(x => x.PictureId);
modelBuilder.Entity<Category>().HasOptional(x => x.ParentCategory).WithMany().HasForeignKey(x => x.ParentCategoryId);
modelBuilder.Entity<Category>().HasMany(x => x.Children).WithOptional().HasForeignKey(x => x.ParentCategoryId);

Category table:

Category table

2

2 Answers

0
votes

Can't tell. Looks basically right .. except for a markup error (below). The JSON is nice to have but I can't tell what you actually have for Category entities after the query completes.

Before we take a next step, what happens when you fix the markup?

Markup mistake

You don't want the parentheses after "Name" in the children template. It should be

<div data-bind="text: ' - ' + Name"></div> <!-- NO PARENS AFTER NAME -->

as it is in your Fiddle.

Cleaner success callback

While you're here, you might consider this alternative syntax which simply replaces the inner array with the query results array; no iteration needed.

.then(function (data) {
        vm.categories(data.results);
        console.log("here: " + data.results.length); -- produces 9
        });
    })
0
votes

Figured it out finally! My mapping setup of the entity was wrong. Just when I thought I couldn't hate the people that made this convoluted api any more, they prove me wrong.

modelBuilder.Entity<Category>().HasOptional(x => x.ParentCategory).WithMany(x => x.ChildrenElements).HasForeignKey(x => x.ParentCategoryId);