0
votes

This is related to the question in: BreezeJS Selecting ComplexType properties

So:

public class Person {
   public int Id {get;set;}
   public string Name {get;set;}
   public Address MyAddress {get;set;}
   public virtual ICollection<Pet> Pets {get;set;}
}

I Would like to call

EntityQuery.from('Person').select('id,name,pets').orderBy('id');

and map to a personBrief object.

I know there is a:

.toType("personBrief") 

extension, but it doesn't seem to "find the object with that description" (Where could I define this?), and online help says no complex types supported.

Then I tried the mapDtosToEntities() function from Jumpstart HotTowel tutorial

This method seems to successfully map only non-array properties. Dto returned from the Breeze query has a pets collection correctly populated. I tried loop-pushing them into an ko.observableArray but event though it populates my new entity, breeze fails with a "Collection navigation property might not be set" error.

In the end I would like to create a Computed in the initializer that says.

personBrief.sumOfPetAges = ko.computed(function() {
            var sum = 0;

            person.pets().forEach(function (i) {
                sum += i.petAge();
            });
            return sum;
        });

Any ideea how I can keep the object graph after the projection? Thanks

1

1 Answers

0
votes

Did you define PersonBrief as an EntityType? I'm betting not ... especially given that you called it "personBrief" in your sample. The toType() method is for casting a simple, flat, known EntityType. So I think you're heading off track a bit here.

Why not cast to Person? Sure some of the Person material is missing (as in CCJS ... although not in this particular example in which you are projecting all data properties). But it's very straightforward. Just write toType('Person'). Did you try that?

If you actually want to define such an EntityType on the client, you can as described in the docs. If you do that, you can use the toType() cast to that type and Breeze will track it in cache. Of course saving such a thing back to the server is another matter. That's doable ... it could be a kind of DTO ... but you'll have to write the interception logic on the server and translate the data into real, server-side persistent entities and this path is beyond the scope of my answer.

Here is some code ... written off the top of my head ... but it should point you in the right direction. Note that I am assuming that Pet is an EntityType, not a ComplexType! At this moment Breeze does not support arrays of ComplexTypes (it will but it doesn't today).

   // Define a PersonBrief type for a given MetadataStore
   function addPersonBriefType(metadataStore) {
        var perType = metadataStore.getEntityType('Person');

        var type = new breeze.EntityType({
            shortName: 'PersonBrief',
            namespace: perType.namespace 
        });
        var idProperty = new breeze.DataProperty({
            nameOnServer: 'Id',
            dataType: breeze.DataType.Int32,
            isPartOfKey: true,
        });
        type.addProperty(idProperty);
        type.addProperty(new breeze.DataProperty({ nameOnServer: 'Name' }));

        // Here's how you define your Pets collection
        // I assume that you already have a Pet type in metadata and
        // it has an inverse navigation back to Person
        // Get the navigation property from Person to Pets
        var assoc = perType.getNavigationProperty('Pets');

        type.addProperty(new breeze.NavigationProperty({
            nameOnServer: 'Pets',
            isScalar: false, // it's a collection
            entityTypeName: assoc.entityType.name,
            foreignKeyNames: assoc.inverse.foreignKeyNames,
            associationName: assoc.associationName
        }));

        metadataStore.addEntityType(type);
        return type;
    }

I was able to do something like this with EmployeePartial in the metadataTests.js of the DocCode sample where the equivalent to Pets is Orders. The comparable projection query is this:

var query = breeze.EntityQuery.from('Employees')
    .where('EmployeeID', 'eq', 1)
    .select('EmployeeID, FirstName, LastName, Orders')
    .toType('EmployeePartial')

Your sumOfPetAges computed should work because there is a PersonBrief type to supplement.

I am winging it myself to be sure. I know it works even if I can't swear by this particular bit of code that I've written here. Let us know how this goes for you.

p.s. While you should be able to navigate from PersonBrief to Pets, do not expect to navigate back from a Pet to a PersonBrief; that navigation property is not defined.