Non scalar navigation properties are not populating with "nodb" conception - breeze

I am using Breeze 1.4.8 and trying to have a list of key/values pairs as Navigation properties with "nodb" conception.
I have 2 simple models:
function configureKeyValuePairDtoType(metadataStore) {
var prop;
var et = new entityType({
shortName: "KeyValuePairDto",
namespace: "DomainClasses.Dtos.Site",
autoGeneratedKeyType: AutoGeneratedKeyType.None
});
et.addProperty(prop = new DataProperty({
name: "key",
dataType: dataType.String,
isNullable: false,
isPartOfKey: true
}));
et.addProperty(prop = new DataProperty({
name: "value",
dataType: dataType.String,
isNullable: false
}));
metadataStore.addEntityType(et);
metadataStore.registerEntityTypeCtor("KeyValuePairDto", null, KeyValuePairDtoInitializer);
function KeyValuePairDtoInitializer(pair) {
}
}
function configureKeyValueStorageDtoType(metadataStore) {
var prop;
var et = new entityType({
shortName: "KeyValueStorageDto",
namespace: "DomainClasses.Dtos.Site",
autoGeneratedKeyType: AutoGeneratedKeyType.None
});
et.addProperty(new DataProperty({
name: "id",
dataType: dataType.Guid,
isNullable: false,
isPartOfKey: true
}));
et.addProperty(prop = new NavigationProperty({
name: "pair",
entityTypeName: "KeyValuePairDto",
isScalar: true
}));
et.addProperty(prop = new NavigationProperty({
name: "pairList",
entityTypeName: "KeyValuePairDto",
associationName: "KeyValueStorageDto_PairList",
isScalar: false
}));
metadataStore.addEntityType(et);
metadataStore.registerEntityTypeCtor("KeyValueStorageDto", null, KeyValueStorageDtoInitializer);
function KeyValueStorageDtoInitializer() {
}
}
Here is response from the server:
In the Breeze model I am getting as result, property pair has correct value, but pairList is just empty.
Please, advice, because it looks like an issue with my models' configuration, but for some reason I cannot find what's wrong.

Could you try this with breeze 1.4.11 just to make sure that we haven't already fixed this?
If it still doesn't work, I'll register a test case and bug for this. Not sure if we'll get this fixed in the next release because we are already in testing for it. But it should be in the following one.

Related

breeze: client-side model with navigationProperty is giving error

When calling addEntityType for ResourceUnavailabilities, I get the error: error configuring an instance of 'NavigationProperty'. The 'entityTypeName' parameter must be a 'string'
I don't get it. I've looked at the tutorial on breeze's website, and I can't tell what I'm doing wrong.
client-side model:
metadataStore.addEntityType({
shortName: 'Unavailability',
namespace: 'ecdt',
dataProperties: {
id: { dataType: DT.Guid, isPartOfKey: true },
startDate: { dataType: DT.DateTimeOffset },
endDate: { dataType: DT.DateTimeOffset },
isDayOff: { dataType: DT.Boolean }
}
});
metadataStore.registerEntityTypeCtor('Unavailability', null, null);
metadataStore.addEntityType({
shortName: 'ResourceUnavailabilities',
namespace: 'ecdt',
dataProperties: {
id: { dataType: DT.Guid, isPartOfKey: true },
resourceId: { dataType: DT.Int32 },
},
navigationProperties: {
unavailabilities: { dataType: 'Unavailability', hasMany: true }
}
});
metadataStore.registerEntityTypeCtor('ResourceUnavailabilities', null, null);
Apart from that everthing works fine. I can create Unavailability entities and also ResourceUnavailabilities entities (as long as I remove the navigation property...)
Also, in the tutorial, you use the nameproperty instead of shortname. If I do that, I get an error
Error configuring an instance of 'EntityType'. Unknown property: 'name'. Is the sample out-of-date ?
Ok, it's solved. The correct mapping is:
metadataStore.addEntityType({
shortName: 'Unavailability',
namespace: 'ecdt',
dataProperties: {
id: { dataType: DT.Guid, isPartOfKey: true },
startDate: { dataType: DT.DateTimeOffset },
endDate: { dataType: DT.DateTimeOffset },
isDayOff: { dataType: DT.Boolean }
},
navigationProperties: {
unavailabilities: { entityTypeName: 'ResourceUnavailabilities', isScalar: true, associationName: "test" }
}
});
metadataStore.registerEntityTypeCtor('Unavailability', null, null);
metadataStore.addEntityType({
shortName: 'ResourceUnavailabilities',
namespace: 'ecdt',
dataProperties: {
id: { dataType: DT.Guid, isPartOfKey: true },
resourceId: { dataType: DT.Int32 },
},
navigationProperties: {
unavailabilities: { entityTypeName: 'Unavailability', isScalar: false, associationName: "test" }
}
});
Looks like the breeze document is not exactly up-to-date.

Breeze How to write entity related queries against local cache

I am trying to figure out how to write a query that will filter my related entities using the executeQueryLocally.
Here is my example:
var queryStageConfigs = breeze.EntityQuery
.from("Stages")
.where("StageConfig.ConfigValue", '==', 'Green')
.expand("StageConfig");
var stageConfigs = self.manager.executeQueryLocally(queryStageConfigs);
This the error I am getting back:
Error: unable to locate property: ConfigValue on entityType: Stages:#
MetadataStore
//Stages Entity
metadataStore.addEntityType({
shortName: "Stages",
//namespace: "MonitoringCenter",
dataProperties: {
id: { dataType: DT.Int64, isPartOfKey: true },
institutionId: { dataType: DT.Int64 },
qualifiedName: { dataType: DT.String },
displayName: { dataType: DT.String },
displayOrder: { dataType: DT.Int64 },
},
navigationProperties: {
institution: {
entityTypeName: "Stages",
isScalar: true,
associationName: "Institution_Stages",
foreignKeyNames: ["institutionId"]
},
stageConfig: {
entityTypeName: "StageConfig",
isScalar: false,
associationName: "Stages_StageConfig"
}
}
});
metadataStore.setEntityTypeForResourceName("Stages", "Stages");
//StageConfig Entity
metadataStore.addEntityType({
shortName: "StageConfig",
//namespace: "MonitoringCenter",
dataProperties: {
id: { dataType: DT.Int64, isPartOfKey: true },
stageId: { dataType: DT.Int64 },
configName: { dataType: DT.String },
configValue: { dataType: DT.String },
},
navigationProperties: {
stages: {
entityTypeName: "StageConfig",
isScalar: true,
associationName: "Stages_StageConfig",
foreignKeyNames: ["stageId"]
}
}
});
metadataStore.setEntityTypeForResourceName("StageConfig", "StageConfig");
I am hand writing the JsonResultsAdpater to get the JSON data into the entities that have created using the metadataStore setting up the relationship between the entities.
When I query the Stages entities I can see the StageConfigs array and it is not empty.
Any clue on what I may be doing wrong?
Any help would be greatly appreciated!
Ok, your example is a little confusing because I can't tell the cardinality of the relationships based on your names. In general, I think of a pluralized name like 'stages' as being a collection of 'Stage' entities (i.e. isScalar = false). But in your case the 'stages' property is actually scalar and its inverse, the 'stageConfig' property, a singularized name, is actually non-scalar. If this assumption is correct then the reason that your query will not work is because the stage.stageConfig property needs to be a scalar in order for your query to work, unless you want to use the 'any/all' operators. i.e. something like
var queryStageConfigs = breeze.EntityQuery
.from("Stages")
.where("StageConfig", "any", "ConfigValue", "==", 'Green');
.expand("StageConfig");
( and shouldn't the query be called 'queryStages' because you are querying and returning 'stages')
Also, just a nit, but its probably a good idea to keep all of your entityType names singular and your resource names plural. This is not a requirement, but it is certainly confusing the way you have one entityType singularized ( StageConfig) and another pluralized (Stages).
I don't see any mention in your code about using the camelCase naming convention, but the example seems to indicate that you are assuming that this is set.

How to configure a non-embedded hasMany relationship with breeze.js

I'm trying to configure a few models with breeze.js
The first is session and I was able to get this working perfectly with a simple query like the below
var query = breeze.EntityQuery.from("sessions").toType("Session");
..but when I tried to add a related "speakers" array to the session I seem to be left with an empty array after the materialization step is complete
Do I need to write a custom json adapter for an api that looks like this?
/api/sessions/
[
{
"id": 1,
"name": "javascript",
"speakers": [
1
]
}
]
/api/speakers/1/
{
"id": 1,
"name": "Toran",
"session": 1
}
Here is my current model configuration (mostly working)
var ds = new breeze.DataService({
serviceName: 'api',
hasServerMetadata: false,
useJsonp: false
});
breeze.config.initializeAdapterInstance("modelLibrary", "backingStore", true);
this.instance = new breeze.EntityManager({dataService: ds});
this.instance.metadataStore.addEntityType({
shortName: "Speaker",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" },
session: { dataType: "Int64" }
},
navigationProperties: {
session: {
entityTypeName: "Session", isScalar: true,
associationName: "session", foreignKeyNames: ["session"]
}
}
});
this.instance.metadataStore.addEntityType({
shortName: "Session",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" },
speakers: { dataType: "Undefined" }
},
navigationProperties: {
speakers: {
entityTypeName: "Speaker", isScalar: false,
associationName: "speakers", foreignKeyNames: ["speakers"]
}
}
});
Thanks for the help !
note** I'm using ember.js (not backbone/ko/angular)
I tried to keep the above brief but if you need absolutely everything, checkout this single js file
https://github.com/toranb/embereeze/blob/master/website/static/website/js/app.js
update
if I remove the "speakers" dataProperty breeze gets fairly unhappy in this block of code (as it's not a dataProperty on the session model)
var fkProps = fkNames.map(function (fkName) {
//fkName is speakers .... yet it's not a data property so bad things happen :(
return parentEntityType.getDataProperty(fkName);
});
var fkPropCollection = parentEntityType.foreignKeyProperties;
// Array.prototype.push.apply(parentEntityType.foreignKeyProperties, fkProps);
fkProps.forEach(function (dp) {
I just did a PR - the association name should be the same on both ends, much like any relational database would have.
this.instance.metadataStore.addEntityType({
shortName: "Speaker",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" },
session: { dataType: "Int64" }
},
navigationProperties: {
sessionModel: {
entityTypeName: "Session", isScalar: true,
associationName: "Speaker_Sessions", foreignKeyNames: ["session"]
}
}
});
this.instance.metadataStore.addEntityType({
shortName: "Session",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" }
},
navigationProperties: {
speakers: {
entityTypeName: "Speaker", isScalar: false,
associationName: "Speaker_Sessions"
}
}
});
So I renamed the association, removed the extra speakers property on the Session (there is no property for the relationship, simply an inverse that should be mapped) and then removed the foreign key on the session as you don't need one there. By assigning passing session down from the API with the models shown above should be enough to let Breeze know
Speakers' have a session property, which is a foreign key pointing to a single session.
Sessions have a collection of speakers, which should be mapped on the other end

Jaydata web api with OData provider -- provider fallback failed error

I'm developing an application with jaydata, OData and web api. Source code is given below:
$(document).ready(function () {
$data.Entity.extend('$org.types.Student', {
Name: { type: 'Edm.String', nullable: false, required: true, maxLength: 40 },
Id: { key: true, type: 'Edm.Int32', nullable: false, computed: false, required: true },
Gender: { type: 'Edm.String', nullable: false, required: true, maxLength: 40 },
Age: { type: 'Edm.Int32', nullable: false, required: true, maxLength: 40 }
});
$data.EntityContext.extend("$org.types.OrgContext", {
Students: { type: $data.EntitySet, elementType: $org.types.Student },
});
var context = new $org.types.OrgContext({ name: 'OData', oDataServiceHost: '/api/students' });
context.onReady(function () {
console.log('context initialized.');
});
});
In above JavaScript code, I defined an entity named Student. In context.onReady() method, I'm getting the following error:
Provider fallback failed! jaydata.min.js:100
Any idea, how I could get rid of this error??
As per suggested solution, I tried to change the key from required to computed. But sadly its still giving the same error. Modified code is given below.
$(document).ready(function () {
$data.Entity.extend('Student', {
Id: { key: true, type: 'int', computed: true },
Name: { type: 'string', required: true}
});
$data.EntityContext.extend("$org.types.OrgContext", {
Students: { type: $data.EntitySet, elementType: Student },
});
var context = new $org.types.OrgContext({
name: 'OData',
oDataServiceHost: '/api/students'
});
context.onReady(function () {
console.log('context initialized.');
});
});
I thinks the issue is with Odata provider because I tried the same code with indexdb provider and its working properly.
The issue is caused by the value oDataServiceHost parameter. You should configure it with the service host, not with a particular collection of the service. I don't know if the provider name is case-sensitive or not, but 'oData' is 100% sure.
For WebAPI + OData endpoints the configuration should look like this:
var context = new $org.types.OrgContext({
name: 'oData',
oDataServiceHost: '/odata'
});

BreezeJS custom type not mapped correctly

This is a little mystifying to me.
I have a custom type defined on the client as such:
var store = manager.metadataStore;
store.addEntityType({
shortName: "ItemContainer",
autoGeneratedKeyType: AutoGeneratedKeyType.Identity,
dataProperties: {
id: { dataType: DataType.Int32, isNullable: false, isPartOfKey: true },
type: { dataType: DataType.Int32, isNullable: false },
isViewed: { dataType: DataType.Boolean, isNullable: false },
itemCount: { dataType: DataType.Int32, isNullable: false }
}
});
store.setEntityTypeForResourceName('Container', 'ItemContainer');
and this is what's passed from the server as an anonymous type (Fiddler):
[{"$id":"1","$type":"<>f__AnonymousType1`4[[System.Int32,mscorlib],
[System.Int32, mscorlib],
[System.Boolean, mscorlib],
[System.Int32, mscorlib]], XYZ",
"Id":43,"Type":1,"IsViewed":true,"ItemCount":19}]
When I examine the returned result on the client thru a breeze query, all the data is correct except the itemCount. The server code generating the type looks like this:
var c = Items.GroupBy(x => new { x.Item.ItemTypeID, x.IsViewed })
.Select(g => new { Id = ID, Type = g.Key.ItemTypeID, IsViewed = g.Key.IsViewed, ItemCount = g.Count() });
the g.Count() (LINQ Count Method) seems to be the culprit here. If I pass a plain integer, it works just fine. Maybe this function gets lazily evaluated, and breeze is not getting the value at the right time?
Thanks

Resources