I develop an application with asp.net mvc + breeze.
So far, I retrieve a specific record (based on id) like this:
var getTransportById = function (transportId, transportObservable) {
return manager.fetchEntityByKey('Transport', transportId, true)
.then(fetchSucceeded)
.fail(queryFailed);
}
function fetchSucceeded(data) {
var s = data.entity;
return ...
}
Now I need to retrieve the same record but need to 'expand' the property named sender which links to another entity (table). I did not find a way to 'expand' one property through fetchEntityByKey so I used a query like this:
var getTransportById = function (transportId, transportObservable) {
var query = EntityQuery.from('Transports')
.where('id', 'eq', transportId)
.expand('Sender')
.orderBy(orderBy.transport);
return manager.executeQuery(query)
.then(fetchSucceeded)
.fail(queryFailed);
}
function fetchSucceeded(data) {
var s = data.results[0];
return ...
}
My question: is it the good way to proceed? Is there another way of doing?
Thanks.
You can create a query from an EntityKey and then expand whichever properties you want. Something like this:
var entityKey = new EntityKey("Transport", transportId);
// expand whichever nav props you want here.
var query = EntityQuery.fromEntityKey(entityKey).expand("Sender").orderBy(...);
return entityManager.executeQuery(query).then( {
...
});
Related
I created a new entry with breeze, on submit i want to immediately get the id of the record using the basic fields that i used to create the record like using email, please how do i get the Id of the new record using breeze.
this is what i have done
bind gotoStep2() with the save button which pass in the value of the textbox to use as predicate,
// the save() method successfully create the record to the database,
function gotoStep2(firstName, lastName, email) {
save();
console.log('Save log')
// Get the ProfileID
return datacontext.profile.getProfileId(firstName, lastName, email)
.then(function (data) {
console.log('Id retrived is: ' + data.Id); // check the value returned
vm.profile = data;
//$location.path('/step-two/' + data.Id);
// Todo: pass the value to the next route
}, function (error) {
logError('Unable to get speaker');
});
}
function getProfileId(firstName, lastName, email) {
var self = this;
var predicate = Predicate.create('firstName', '==', firstName)
.and('lastName', '==', lastName)
.and('email', '==', email);
var profiles = [];
return EntityQuery.from('Profiles')
.select('id')
.where(predicate)
.toType(entityName)
.using(self.manager).execute()
.then(querySucceeded, self._queryFailed);
function querySucceeded(data) {
profiles = data.results;
self.log('Retrieved [Profile by email] from remote data source', profiles.length, true);
return profiles;
}
}
from the above query dont always get any return value
Thanks
Not entirely sure I understand your question, but it sounds like you want to get the id of a newly saved record immediately after the save. If so then the answer below applies.
When the save promise resolves it returns both the list of saved entities as well as a keyMappings array for any entities whose ids changed as a result of the save. i.e. a mapping from temporary to real ids. i.e. (Documented here: http://www.breezejs.com/sites/all/apidocs/classes/EntityManager.html#method_saveChanges)
myEntityManager.saveChanges().then(function (saveResult) {
// entities is an array of entities that were just saved.
var entitites = saveResult.entities;
var keyMappings = saveResult.keyMappings;
keyMappings.forEach(function(km) {
var tempId = km.tempValue;
var newId = km.realValue;
});
});
On the other hand if you have an entity and you just want its 'key' you can use the EntityAspect.getKey method. (see http://www.breezejs.com/sites/all/apidocs/classes/EntityAspect.html#method_getKey)
// assume order is an order entity attached to an EntityManager.
var entityKey = order.entityAspect.getKey();
I have the following code that went from this:
var getUserByGuid = function (guid, entityObservable) {
return datacontext.manager.user.fetchEntityByKey('User', guid, true)
.then(fetchSucceeded)
.fail(queryFailed);
function fetchSucceeded(data) {
var entity = data.entity;
if (ko.isWriteableObservable(entityObservable))
entityObservable(entity);
return entity;
}
function queryFailed(error) {
logger.error(error);
}
};
to this:
var getUserByGuid = function (guid, entityObservable) {
if (datacontext.manager.user.metadataStore.isEmpty()) {
return datacontext.manager.user.metadataStore.fetchMetadata('breeze/user')
.then(function () {
return datacontext.manager.user.fetchEntityByKey('User', guid, true)
.then(fetchSucceeded)
.fail(queryFailed);
});
} else {
return datacontext.manager.user.fetchEntityByKey('User', guid, true)
.then(fetchSucceeded)
.fail(queryFailed);
}
function fetchSucceeded(data) {
var entity = data.entity;
if (ko.isWriteableObservable(entityObservable))
entityObservable(entity);
return entity;
}
function queryFailed(error) {
logger.error(error);
}
};
Notice the extra check to verify metadataStore is ready? Since I am making a call to fetch, I would assume this check would happen internally but for some reason it is not.
My code runs well with the following "work-around" in place but wanted to bring this to light.
Updated 3/1/2014
As of Breeze 1.4.9 (or later), available now this has been fixed.
Previous post
I think you are right. The problem, I think, is that fetchEntityByKey doesn't actually have to perform a fetch when you tell it to search the local cache first. But in this case, if you don't have metadata then the localQuery fails. I'll try to get this fixed in the next release, probably out later this week.
I have a bulk insert screen which allows the user to insert products line by line.. Each product has it's own Units of measurement.
Here is my save changes Code:
save = function (product) {
var entitiesToSave = product.units().slice();
entitiesToSave.push(product);
var so = new breeze.SaveOptions({ allowConcurrentSaves: true })
return manager.saveChanges([entitiesToSave],so)
.then(saveSucceeded)
.fail(saveFailed);
}
Once I try to save; I get this message:
The 'entities' parameter is optional or it must be an array where each element must be an entity
Modifying the code to:
save = function (product) {
var so = new breeze.SaveOptions({ allowConcurrentSaves: true })
return manager.saveChanges([product,product.units()[0]],so)
.then(saveSucceeded)
.fail(saveFailed);
}
Works fine for one product unit.. However, I needed to save a specific product with all of it's units
in one shot..
Any help is appreciated.
For those who might have similar issue; I got it fixed by modifying the code to the following:
save = function (product) {
var entitiesToSave = new Array(product);
product.Units().forEach(function (Unit) {
entitiesToSave.push(Unit);
});
var so = new breeze.SaveOptions({ allowConcurrentSaves: true })
return manager.saveChanges(entitiesToSave,so)
.then(saveSucceeded)
.fail(saveFailed);
}
Regards to all.
My collection and model like this:
detail_userid = 0;
detail_contactid = 0;
var ContactDetail = Backbone.Model.extend({
urlRoot: URL_CONTACTS1+detail_userid+"/"+detail_contactid
});
var ContactDetailCollection = Backbone.Collection.extend({
model: ContactDetail,
url: URL_CONTACTS1+detail_userid+"/"+detail_contactid
})
The entrance is:
ContactDetailManagePageModel.prototype.init = function(m,n){
detail_userid = m;
detail_contactid = n;
var myContactDetails = new ContactDetailCollection();
var contactDetailListView = new ContactDetailListView({
collection: myContactDetails
});
myContactDetails.fetch({reset:true});
}
But when it runs,the url is :http://localhost:8080/ws/users/contacts/0/0,it means that the assignment to detail_userid and detail_contactid is unsuccessful,I don't know why.
Hope for your help.Thanks.
I think you are statically definining the urlRoot and url properties before you are running the init of the PageModel (not quite sure where you are getting m and n from though...)
Both url and urlRoot can be a function, so you can pass in options during instantiation and have them dynamically set on the model.
Simple example covering defining the collection and then creating one
var ContactDetailCollection = Backbone.Collection.extend({
model: ContactDetail,
url: function(){
return URL_CONTACTS1 + this.options.detail_userid + "/" + this.options.detail_contactid;
}
});
var myContactDetails = new ContactDetailCollection({
detail_userid: foo,
detail_contactid: bar
});
As I mentioned, I'm not sure what your init function is doing, I'm guessing it's something custom from your app that I don't need to worry about.
I'm fairly sure the main thing to take away is to set url and urlRoot dynamically
I would fulfill the accepted answer with few remarks.
First parameter when initializing Backbone.Collection is array of models, then options. To create an empty collection with options you should do next
var c = new Backbone.Collection(null, {opt1: val1, opt2: val2});
Actually, you can't access this.options in url function, bec. there are no options like in a model. What you can do, is assign required properties from options upon initialization.
initialize: function (models, options) {
// `parseInt()` is used for consistency that `id` is numeric, just to be sure
this.detail_userid = parseInt(options.detail_userid);
this.detail_contactid = parseInt(options.detail_contactid);
}
Later you can access them like this:
url: function() {
return URL_CONTACTS1 + this.detail_userid + "/" + this.detail_contactid;
}
I wanted to use the HATEOAS href from one model to fetch data of another model. It worked to simply set the url on the newly created collection instead of defining it right away in the constructor.
var DailyMeasuresCollection = Backbone.Collection.extend({
//url : set dynamically with collection.url = url
model : DailyMeasuresModel,
parse : function(data) {
return data._embedded.dailyMeasures;
}
});
var DailyMeasuresTopicListItemView = Backbone.View.extend({
//...
events : {
'click .select-topic' : 'onClick'
},
onClick : function() {
var topicMeasures = new DailyMeasuresCollection()
topicMeasures.url = this.model.attributes._links.measures.href // <- here assign
var topicMeasuresView = new DailyMeasuresListView({
collection : topicMeasures
});
topicMeasures.fetch()
}
});
I wish to return a single ScPollOption item using a Stored Procedure via the code below:
public ScPollOption FetchPollOptionByID(int optionID)
{
StoredProcedure sp = SPs.ScPollOptionGetOptionByID(optionID);
return sp;
}
When working with a query I would use:
ExecuteSingle<ScPollOption>()
but SubSonic only allows for sp.ExecuteTypedList<> and sp.ExecuteScalar<>.
How can I return a single ScPollOption item?
Thanks
Dan
I know it's not terribly attractive, but this would work if you're able to use the LINQ extensions:
sp.ExecuteTypedList<ScPollOption>().FirstOrDefault();
You could also execute an IDataReader and inflate the ScPollOption object manually:
ScPollOption item;
using (IDataReader reader = sp.ExecuteReader())
{
if (reader.Read())
{
item = new ScPollOption();
item.SomeProperty = reader.GetValue(0);
// Set additional properties
}
}
return item;