Breeze - define key to add entity - breeze

I want to add an Entity to my Manager.
The manager is saved in my MasterViewmodel, and I'm working with knockout.
Error: Cannot attach an object to an EntityManager without first setting its key or setting its entityType 'AutoGeneratedKeyType' property to something other than 'None'
My code:
var item = {
GuidUser: masterViewModel.UserID,
GuidProject: ProjectID,
Start: startTime,
End: stopTime,
Description: workDone,
IdCustomer: null,
timestampId: null,
Charged: false,
ToCharge: toCharge,
};
var item2 = masterViewModel.breezeProjectManager().createEntity('Timestamp', item);
masterViewModel.breezeProjectManager().addEntity(item2);
But how to set a Key?

Try the following:
var item2 = masterViewModel.breezeProjectManager()
.createEntity('item', { timestampId: breeze.core.getUuid() });

When any EntityType is first defined it should have at least one DataProperty that has it's 'isPartOfKey' property set to true. The metadata for any EntityType is either materialized as a result of the metadata being returned from the server or is created on the client. In either case, the "EntityType' metadata must be created before any entities of the type can be created.
My guess is that you have not yet either fetched the metadata or created it, when you first tried to create your entity. In your case, you can make a fetchMetadata call before you try to create your entity. i.e.
breezeProjectManager().metadataStore.fetchMetadata().then(function() {
.. perform your creation and add logic here.
}
The other possibility is that whichever field ( or fields) are defined with 'isPartOfKey' = true, have not been set to a nonnull value before calling 'addEntity'.

Related

breeze createEntity not initializing one of the navigation property

I am creating a breeze entity using createEntity of entitymanager. Upon creation I find that only 1 of its navigation property is null whereas others are assigned.
var chargeEntity = {
ClientId: data.ClientId,
PatientId: data.PatientId,
AssessmentLogId: data.AssessmentLogId,
MedicalRecordNbr: data.Patient.MedicalRecordNbr,
AssessmentTypeCd: data.AssessmentType.AssessmentTypeCd,
ReviewDate: new Date(),
Qty: 1,
InsertDate: new Date(),
ProductId: data.ProductId
};
var charge = datacontext.createEntity('Charge', chargeEntity);
I find that in the charge entity, AssessmentLog navigation property is null where as others like Client, Patient and Product are assigned.
What could be the reason ?
After debugging for a while, I found that in breeze.debug.js, in the function below:
proto._findEntityGroup = function (entityType) {
return this._entityGroupMap[entityType.name];
};
_entityGroupMap does not contain an entry for the navigation property AssessmentLog, hence that property is being set as null.
The entity AssessmentLog was not in cache for the AssessmentLogId, that's why the navigation property was being set as null.
I executed a breeze query for the AssessmentLogId, and then the charge entity's AssessmentLog was correctly set.

Breeze - How to Load Navigation property from cache

I am getting a single entity by using a method fetchEntityByKey, after that I am loading navigation property for the entity by entityAspect.loadNavigationProperty. But loadNavigationProperty always make a call to the server, what I am wondering if I can first check it from cache, if it is exist then get it from there otherwise go the server. How is it possible? Here is my current code
return datacontext.getProjectById(projectId)
.then(function (data) {
vm.project = data;
vm.project.entityAspect.loadNavigationProperty('messages');
});
Here is a function that I encapsulated inside datacontext service.
function getProjectById(projectId) {
return manager.fetchEntityByKey('Project', projectId)
.then(querySucceeded, _queryFailed);
function querySucceeded(data) {
return data.entity;
}
}
Also, how is it possible to load navigation property with some limit. I don't want to have all records for navigation property at once for performance reason.
You can use the EntityQuery.fromEntityNavigation method to construct a query based on an entity and a navigationProperty . From there you can execute the resulting query locally, via the EntityManager.executeQueryLocally method. So in your example once you have a 'project' entity you can do the following.
var messagesNavProp = project.entityType.getProperty("messages");
var query = EntityQuery.fromEntityNavigation(project, messagesNavProp);
var messages = myEntityManager.executeQueryLocally(query);
You can also make use of the the EntityQuery.using method to toggle a query between remote and local execution, like this:
query = query.using(FetchStrategy.FromLocalCache);
vs
query = query.using(FetchStrategy.FromServer);
please take a look here: http://www.breezejs.com/sites/all/apidocs/classes/EntityManager.html
as you can see fetchEntityByKey ( typeName keyValues checkLocalCacheFirst ) also have a third optional param that you can use to tell breeze to first check the manager cache for that entity
hope this helps

Breeze-Unreferenced Entity in Manager

I am developing a Single Page App using Hot Towel Template, using breeze...and I have come across a peculiar problem, and I am unable to figure out the internal working which causes it...
I have a Programmes table, and the Programmes table has a foreign key to Responses, so the structure of Programmes is:
Id, ResponseID, Name and Date
and the Page has Name and Date, the foreign comes from RouteData.
and for one ResponseId in Programmes table, I want to save only on Programme.
So, when user comes to this page, it check the Programmes table that if it has an Entry for that particular Response Id, if yes, it goes in Edit case and if not it goes to Add a new entry case.
To achieve this, what I am doing is below:
var objTempProgramme = ko.observable();
var objProgramme = ko.observable();
function activate(routeData) {
responseId = parseInt(routeData.responseId);
// Create a Programme Entity
objProgramme(datacontext.createProgramme());
// Fill in a Temporary Observable with Programmes data
datacontext.getEntitiesDetailsByRelativeId('responseID', responseId , 'Programmes', objTempProgramme, true).then(function(){
// Check if Programmes Exists
if (objTempProgramme() != null && objTempProgramme() != undefined) {
// What I am doing here is filling my Programmes Entity with data coming from database (if it is there)
objProgramme(objTempProgramme());
} else {
// The Else Part assigns the Foreign Key (ResponseId) to my Entity Created above
objProgramme().responseID(responseId);
}
});
}
In datacontext.js:
var createProgramme = function () {
return manager.createEntity(entityNames.programme);
}
var getEntitiesDetailsByRelativeId = function (relativeIdName, relativeId, lookupEntity, observable, forceRefresh) {
var query = entityQuery.from(lookupEntity).where(relativeIdName, "==", relativeId);
return executeGetQuery(query, observable, forceRefresh);
};
Now when I call manager.saveChanes on my page, I would Expect objProgramme to be saved, in any case, be it edit or be it save,
but what breeze is doing here is that though it is filling objTempProgramme in objProgramme, but it is also leaving the entity objProgramme unreferenced with its manager, so that when I call save, it tries to save that entity too (2 entities in total, objProramme and one unreferenced one), but that entity does not have foreign key set and it fails..but my question is why?
Assigning one entity to another does not mean all its properties get assigned to another? And why is that unreferenced entity present?

How do I set a property on a breeze entity client-side?

I've tried drilling down into the object and looking at the docs but haven't found anything. I've created an entity and I need to assign some properties manually. I see _backingStore and entityAspect on the object... and I know the property names but don't know how to set them via the breeze entity.
In case it matters, I'm creating a new object and then copying properties over from another object to facilitate cloning.
function createDocument() {
var manager = datacontext.manager;
var ds = datacontext.serviceName;
if (!manager.metadataStore.hasMetadataFor(ds)) {
manager.fetchMetadata(ds).then(function () {
return manager.createEntity("Document");
})
}
else {
return manager.createEntity("Document");
}
}
function cloneDocument(doc) {
var clonedDocument = createDocument();
// Copy Properties Here - how?
saveChanges()
.fail(cloneFailed)
.fin(cloneSucceeded);
}
Not knowing what your properties might be, here are two scenarios -
function cloneDocument(doc) {
var clonedDocument = createDocument();
clonedDocument.docId(doc.docId());
clonedDocument.description(doc.description());
saveChanges()
.fail(cloneFailed)
.fin(cloneSucceeded);
}
There are a few things to note here - I am assuming you are using Knockout and needing to set the properties. If you are not using Knockout then you can remove the parans and use equals -
clonedDocument.docId = doc.docId;
I believe this is true for if you are not using Knockout (vanilla js) and if you are using Angular, but I have not used Breeze with Angular yet so bear with me.
And here's another way that works regardless of model library (Angular or KO)
function cloneDocument(doc) {
var manager = doc.entityAspect.entityManager; // get it from the source
// Check this out! I'm using an object initializer!
var clonedDocument = manager.createEntity("Document", {
description: doc.description,
foo: doc.foo,
bar: doc.bar,
baz: doc.baz
});
return clonedDocument;
}
But beware of this:
clonedDocument.docId = doc.docId; // Probably won't work!
Two entities of the same type in the same manager cannot have the same key.
Extra credit: write a utility that copies the properties of one entity to another without copying entityAspect or the key (the id) and optionally clones the entities of a dependent navigation (e.g., the order line items of an order).

Breeze registerEntityTypeCtor not working

I am working on a Hottowel project and I want to format some data passed on from database to Breeze, but it looks like the ctor is not getting registered.
What am I doing wrong?
In datacontext.js:
var manager = configureManager();
function configureManager() {
var mng = new breeze.EntityManager('breeze/data');
breeze.NamingConvention.camelCase.setAsDefault();
model.configureMetadataStore(mng.metadataStore);
return mng;
}
In model.js:
function configureMetadataStore(metadataStore) {
metadataStore.registerEntityTypeCtor
('UserInfo', null, userInfoInitializer);
}
function userInfoInitializer() {
if (this.Email == "")
this.Email = '---';
this.CreateDate = formatDateTime(this.CreateDate);
}
function formatDateTime(DateTime) {
return moment.utc(DateTime).format('DD. MM. YYYY. [у] hh:mm');
}
Datacontext has a reference to model, the data is transferred from database and appears on the screen, but is not formatted. console.log() calls from userInfoInitializer() are not appearing.
When I am constructing an entity, my constructor needs to have an entity to construct. I have not tried your above code but I believe that Breeze passes an entity in and you need to give that entity properties. Using this. MAY work but it is the first thing that stands out to me.
function userInfoInitializer(user) {
if (user.Email == "")
user.Email = "---";
2nd - What is your entity named in your model? Is it UserInfo or just User? You probably already know this but you need to make sure when you are adding a constructor you use the properly named Entity.
3rd - If you are using camelCase then you need to leave the first letter of the property lowercase. Ex . user.email and user.createDate.
Last, I can't tell if you are creating a 'createDate' in the constructor or that is being passed from your model. If it is indeed a property you are creating I would recommend making it an knockout observable or computed property. If it is coming from the database then you need to do something like
if (!user.createDate) { } //set it
Remember that all of the entities being returned from the database will be given that property, so if you have entities that already have a createDate in your example you are overriding that date. If you want to set createDate to now then I would move that into your method where you are creating the object.

Resources