var bindings = storageService.uploadComponent(repoId, assetId, resourceId, UUID.randomUUID().toString(), null, null, "text/plain", Mono.just(componentPart));
StepVerifier.create(bindings).consumeNextWith(b -> {
var stagedUploadRecord = stagedUploadRepository.findRevision(repoId, assetId, resourceId, b.getRevisionId());
StepVerifier.create(stagedUploadRecord).expectNextCount(1L).verifyComplete();
}).verifyComplete();
This code calls a functions which adds records to several tables and produces a publisher, Mono. I would like to verify that there is one binding and then verify that records were added to the individual tables, but I need some info from the bindings to read the records from the individual tables.
So I thought that I could do this using consumeNextWith, but as soon as I put the StepVerifier.create inside the consumeNextWith the whole pipeline freezes.
Related
I'm a newbie in NetSuite Scripting and was recently asked to apply the value from a date field (custbody_expiration_date) on item receipt transaction body to the expiration date field in the inventory details of all items when the item receipt is created.
Since there is no way to create a workflow on inventory details, I've managed to work out below codes however I'm keeping getting all sorts of different error message. Below is one of them after I click on save on item receipt.
Notice (SuiteScript)
org.mozilla.javascript.EcmaError: TypeError: Cannot find function getCurrentLineItemValue in object standard record. (/SuiteScripts/ARROW/Expiration_date_apply_to_all (1).js#27)
I am very confused on the difference between dynamic and standard mode, which functions should be used in which mode? Also, I am a bit hesitated on whether user event script is the correct way to go?
/**
*#NApiVersion 2.0
*#NScriptType UserEventScript
*#NModuleScope Public
*/
define(['N/record','N/search'], function (record, search) {
function beforeSubmit(context) {
var IRrecord = context.newRecord;
var numberOfLineItems = IRrecord.getLineCount({
sublistId: 'item'
});
var expirationdate = IRrecord.getValue({
fieldId: 'custbody_expiration_date'
});
for (var i=1; i<=numberOfLineItems; i++){
IRrecord.setSublistValue({
sublistId: 'item',
fieldId: 'item',
line: i,
value: true
});
//First get Lot Number and Quantity
var lotNumber = IRrecord.getCurrentLineItemValue('item', 'receiptinventorynumber');
var quantity = IRrecord.getCurrentLineItemValue('item', 'quantity');
var inventoryDetail = IRrecord.createCurrentLineItemSubrecord('item','inventorydetail');
inventoryDetail.selectNewLineItem('inventoryassignment');
inventoryDetail.setCurrentLineItemValue('inventoryassignment', 'issueinventorynumber', lotNumber);
inventoryDetail.setCurrentLineItemValue('inventoryassignment', 'quantity', quantity);
inventoryDetail.setCurrentLineItemValue('inventoryassignment', 'expirationdate', expirationdate);
inventoryDetail.commitLineItem('inventoryassignment');
inventoryDetail.commit();
IRrecord.commitLineItem('item');
}
nlapiSubmitRecord(IRrecord);
}
return {
beforeSubmit: beforeSubmit
}
});
Dynamic records are the kind you see client-side (as a rule) - modify a field value and some other field becomes refreshed and updated in real time. Forms sometimes need to have their fields filled in a particular order to prevent form completion errors triggering or field sourcing to work. For example, when entering a sales order, selecting the customer then defaults the sales tax when items are added to the order. Errors may be thrown at any point before the record save because a field is triggering dynamic sourcing (updating other fields), based on what has been entered.
Standard mode is - less dynamic. You populate the fields of the record in any order you choose, and when the save is performed, you choose whether sourcing (updating other fields from the data available) is triggered. Any errors in data entry are reported when the save is performed. I think it also has a lower client-side load as there are fewer AJAX queries being triggered.
Both are available in client-side and server-side javascript, but some record types cannot be updated client-side and must be done server-side using workflow actions, User Event, Restlet, Suitelets, or scheduled scripts. To the best of my knowledge, inventory subrecords on fulfillments, receipts and the like are one such type.
The way lines are updated changes between dynamic and standard mode. In dynamic mode, lines are selected, updated then committed and the methods used would be :
selectLine
setCurrentLineItemValue
commitLine (only do this if actually changing the line)
For standard mode, the way of changing lines is only to use setSublistValue and include the line number in the parameters.
Workflow action scripts will load the record in dynamic mode, but the load method can be investigated using the isDynamic() method on the record.
The other thing is, in SuiteScript 2, sublist lines are indexed from 0, not from 1 as your script is using. What's confusing is, in Suitescript 1, indexing was from 1. The code is using a mix of v1 & v2. nlapiSubmitRecord is v1, IRrecord.save is v2.
And for more information, see SuiteAnswer 79715 which explains how to set a value on the inventory detail on an item receipt. The example reloads the record in standard mode and updates the inventoryStatus field. SuiteAnswer 45372 explains the Record object and the difference between standard and dynamic modes. Take a look at SuiteAnswer 67605 which explains the basics of SuiteScript v2. SuiteAnswers is an amazing resource and the search is surprisingly good. I can also recommend Eric T Grubaugh's site (#erictgrubaugh) which has some great videos including comparisons between v1 & v2.
I've been adding records to a dynamic module via the API and in the process during my experimentation I added a bunch of records that weren't associated correctly with any valid parent record.
I've checked and so far I can see that Sitefinity stores data about these records in a number of tables:
mydynamiccontenttype_table
sf_dynamic_content
sf_dynmc_cntnt_sf_lnguage_data
sf_dynmc_cntent_sf_permissions
I would like to clean up the database by deleting these records but I want to make sure I don't create more problems in the process.
Anyone know if there are more references to these dynamic content type records or a process to safely delete them?
There are probably other tables, so your safest option would be to delete the items using the Sitefinity API.
Just get the masterId of the item and use a code like this:
public static void DeleteDataItemOfType(this DynamicModuleManager manager, string type, Guid Id)
{
Type resolvedType = TypeResolutionService.ResolveType(type);
using (var region = new ElevatedModeRegion(manager))
{
manager.DeleteDataItem(resolvedType, Id);
manager.SaveChanges();
}
}
I'm using early-bound entities, generated by CrmSvcUtil, and I'm testing the SDK by retrieving an account entity:-
var account = myContext.AccountSet.FirstOrDefault(o => o.Id == Guid.Parse("..."));
(BTW is there an easier way to retrieve an entity by ID?!)
Looking at the account object that is returned, I can see various properties of type OptionSetValue (e.g. "PreferredContactMethodCode"). How do I get the actual item from this OptionSetValue object?
Similarly, there are numerous properties of type EntityReference, which contains an Id and LogicalName (the entity name I presume). How can I populate such a property - is it one of the Get... methods? And do these have to be called separately, or is it possible to "pre-fetch" certain relationships as part of the initial query that retrieves the account entity?
Similarly with the various IEnumerable<> properties (which presumably correspond to 1-M entity relationships), e.g. a property called "opportunity_customer_accounts" of type IEnumerable. How do I populate one of these properties? And (again) does this have to be done as a separate query/method call, or can it be "pre-fetched"?
Retrieve
I'm not really sure how much simpler the retrieve operation could get but for a single record the user of the context is probably overkill. So you could retrieve a specific record where you know directly with the IOrganizationService:
account = service.Retrieve("account", Guid.Parse("..."), new ColumnSet(true));
Option Set Labels
For the OptionSet labels you can look at my answer here: How to get the option set from a field in an entity in CRM 2011 using crm sdk and C#.
If you need the label for multiple OptionSet's on an entity you may want to just retrieve the Entity's metadata once (http://srinivasrajulapudi.blogspot.com/2012/01/retrieve-entity-metadata-in-crm-2011.html):
string entityName ="contact";
// Get the metadata for the currently list's entity
// This metadata is used to create a "Property Descriptor Collection"
RetrieveEntityRequest mdRequest = new RetrieveEntityRequest ( )
{ EntityFilters = EntityFilters.All,
LogicalName = entityName,
RetrieveAsIfPublished = false
};
// Execute the request
RetrieveEntityResponse entityResponse = ( RetrieveEntityResponse ) this.ServiceProxy.Execute ( mdRequest );
EntityMetadata entityData = entityResponse.EntityMetadata;
//To Get Option Set Data
var preferdList= ( entityData.Attributes.Where ( p => p.LogicalName == "preferredcontactmethodcode" ) ).ToList ( ).FirstOrDefault ( ); ;
if ( preferdList != null ) {
PicklistAttributeMetadata optionList= preferdList as PicklistAttributeMetadata;
OptionSetMetadata opValues= optionList.OptionSet;
foreach ( var op in opValues.Options ) {
preferedMethod.Add ( new OptionSet { Value = op.Value.Value, Text = op.Label.LocalizedLabels[0].Label.ToString() } );
}
}
EntityReference()
To set an EntityReference typed field:
account.primarycontact = new EntityReference("contact", Guide.Parse("..."));
If they have a value and you requested the column in your ColumnSet() they should be populated, so I'm not really sure I understand your question. If you mean, you want the full record then you need to do a service.Retrieve(...) for the record.
Related Entities (i.e., opportunity_customer_accounts)
This is where using an OrganizationServiceContext makes life easier (https://msdn.microsoft.com/en-us/library/gg695791.aspx):
context.LoadProperty(contact, "transactioncurrency_contact");
// read related entity dynamically
var currency = contact.GetRelatedEntity("transactioncurrency_contact");
Console.WriteLine(currency.GetAttributeValue("currencyname"));
// read related entity statically
var currencyStatic = contact.transactioncurrency_contact;
Console.WriteLine(currencyStatic.CurrencyName);
If you are not using an OrganizationServiceContext you can try using a QueryExpression using LinkedEntities, although I've never done this to populate an early-bound entity so I don't know if it works (perhaps someone will add a comment with the answer.)
Let's say I have database with two tables - Groups and Items.
Table Groups has only two columns: Id and Name.
Table Items has three columns: Id, GroupId and Name.
As you can see, there is one-to-many relation between Groups and Items.
I'm trying to build a web service using WCF and LINQ. I've added new LINQ to SQL classes file, and I've imported these two tables. Visual Studio has automatically generated proper classes for me.
After that, I've create simple client for the service, just to check if everything is working. After I call GetAllGroups() method, I get all groups from Groups table. But their property Items is always null.
So my question is - is there a way to force WCF to return whole class (whole Group class and all Items that belong to it)? Or is this the way it should behave?
EDIT: This is function inside WCF Service that returns all Groups:
public List<Group> GetAllGroups()
{
List<Group> groups = (from r in db.Groups select r).ToList();
return groups;
}
I've checked while debugging and every Group object inside GetAllGroups() function has it's items, but after client receives them - every Items property is set to null.
Most likely, you're experiencing the default "lazy-loading" behavior of Linq-to-SQL. When you debug and look at the .Items collection - that causes the items to be loaded. This doesn't happen however when your service code runs normally.
You can however enforce "eager-loading" of those items - try something like this:
(see Using DataLoadOptions to Control Deferred Loading or LINQ to SQL, Lazy Loading and Prefetching for more details)
public List<Group> GetAllGroups()
{
// this line should really be where you *instantiate* your "db" context!
db.DeferredLoadingEnabled = false;
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Group>(g => g.Items);
db.LoadOptions = dlo;
List<Group> groups = (from r in db.Groups select r).ToList();
return groups;
}
Do you get the Items collection populated now, when you call your service?
How would I use nHibernate,configured by fluent nhibernate if it makes any difference, to load an entity using natural/alternate key in some cases, rather than the primary key when using the Load method on an ISession.
I still need the functionality to allow me to do both, and in the majority of cases, the entity will be loaded via the PKey, but in some cases (where an external system is involved), I need to select the record using the natural key.
I'd like to keep the performance benefit Load allows, rather than do a query etc.
// Current
int countryID = 1; // from normal input source
Address a = new Address();
a.Country = session.Load<Country>(countryID);
session.SaveOrUpdate(a);
// Required
string countryCode = "usa"; // from external input source
Address a2 = new Address();
a2.Country = session.LoadViaNatualKeySomehow<Country>(c=> c.Code, countryCode); // :)
session.SaveOrUpdate(a2);
AFAIK, it is not possible. As you can see in Ayendes post, there is a query syntax for criteria, the only natural ID in the whole NHibernate API as far as I know. This query translates into a "normal" query, except of the second level cache handling as described in this post.
It would be nice if it wouldn't at least flush the session.
one simple performance enhancement you can do is turning off auto flush before querying by the (immutable!) natural ID:
session.FlushMode = FlushMode.Never;
session.CreateQuery(...by natural id ...);
session.FlushMode = FlushMode.Auto;
This can make a big difference, but does of course not compete to Load.
The reason why it doesn't exist is most probably the fact the entities in the session are all identified by the id.
If you had it:
var entity1 = session.Load<Entit>(id);
// does not exist
var entity2 = session.LoadByNaturalKey(natural id);
How could NH determine that the id and the natural id are identifying the same object, without loading them from the database? The whole session cache gets into trouble.