I want to get all the attributes from my "Actual Item Inventry" (From Stock Items Form) so i have:
PXResultset<CSAnswers> res = PXSelectJoin<CSAnswers,
InnerJoin<InventoryItem,
On<CSAnswers.refNoteID, Equal<Current<InventoryItem.noteID>>>
>
>.Select(new PXGraph());
But, this returns me 0 rows.
Where is my error?
UPDATED:
My loop is like this:
foreach (PXResult<CSAnswers> record in res)
{
CSAnswers answers = (CSAnswers)record;
string refnoteid = answers.RefNoteID.ToString();
string value = answers.Value;
}
... but i can not go inside foreach.
Sorry for the English.
You should use an initialized graph rather than just "new PXGraph()" for the select. This can be as simple as "this" or "Base" depending on where this code is located. There are times that it is ok to initialize a new graph instance, but also times that it is not ok. Not knowing the context of your code sample, let's assume that "this" and "Base" were insufficient, and you need to initialize a new graph. If you need to work within another graph instance, this is how your code would look.
InventoryItemMaint graph = PXGraph<InventoryItemMaint>.CreateInstance<InventoryItemMaint>();
PXResultset<CSAnswers> res = PXSelectJoin<CSAnswers,
InnerJoin<InventoryItem, On<CSAnswers.refNoteID, Equal<Current<InventoryItem.noteID>>>>>
.Select(graph);
foreach (PXResult<CSAnswers> record in res)
{
CSAnswers answers = (CSAnswers)record;
string refnoteid = answers.RefNoteID.ToString();
string value = answers.Value;
}
However, since you should be initializing graph within a graph or graph extension, you should be able to use:
.Select(this) // To use the current graph containing this logic
or
.Select(Base) // To use the base graph that is being extended if in a graph extension
Since you are referring to:
Current<InventoryItem.noteID>
...but are using "new PXGraph()" then there is no "InventoryItem" to be in the current data cache of the generic base object PXGraph. Hence the need to reference a fully defined graph.
Another syntax for specifying exactly what value you want to pass in is to use a parameter like this:
var myNoteIdVariable = ...
InventoryItemMaint graph = PXGraph<InventoryItemMaint>.CreateInstance<InventoryItemMaint>();
PXResultset<CSAnswers> res = PXSelectJoin<CSAnswers,
InnerJoin<InventoryItem, On<CSAnswers.refNoteID, Equal<Required<InventoryItem.noteID>>>>>
.Select(graph, myNoteIdVariable);
foreach (PXResult<CSAnswers> record in res)
{
CSAnswers answers = (CSAnswers)record;
string refnoteid = answers.RefNoteID.ToString();
string value = answers.Value;
}
Notice the "Required" and the extra value in the Select() section. A quick and easy way to check if you have a value for your parameter is to use PXTrace to write to the Trace that you can check after refreshing the screen and performing whatever action would execute your code:
PXTrace.WriteInformation(myNoteIdVariable.ToString());
...to see if there is a value in myNoteIdVariable to retrieve a result set. Place that outside of the foreach block or you will only get a value in the trace when you actually get records... which is not happening in your case.
If you want to get deep into what SQL statements are being generated and executed, look for Request Profiler in the menus and enable SQL logging while you run a test. Then come back to check the results. (Remember to disable the SQL logging when done or you can generate a lot of unnecessary data.)
Related
Apologies if this question has been answered elsewhere, I have had trouble finding any resources on this.
The scenario is this. I have created a custom field in the Tax Preferences screen called Usrapikey.
This value holds an api key for a call that gets done in some custom business logic.
The custom business logic however occurs on the Taxes screen.
So within the event handler I need to access that API key value from the other screen. I have tried instantiating graphs and using linq and bql but to no avail.
below is what I have currently and my error is: No overload for method 'GetExtension' takes 1 arguments
If I am going about this the wrong way please let me know if there is a more civilized way to do this
protected virtual void _(Events.FieldUpdated<TaxRev, TaxRev.startDate> e)
{
var setup = PXGraph.CreateInstance<TXSetupMaint>();
var TXSetupEX = setup.GetExtension<PX.Objects.TX.TXSetupExt>(setup);
var rateObj = GetValues(e.Row.TaxID, TXSetupEX.Usrapikey);
decimal rate;
var tryRate = (Decimal.TryParse(rateObj.rate.combined_rate, out rate));
row.TaxRate = (decimal)rate * (decimal)100;
row.TaxBucketID = 1;
}
Many Thanks!
Well, acumatica support got back. It seems if you want to access the base page use:
TXSetup txsetup = PXSetup<TXSetup>.Select(Base);
To get the extension use:
TXSetupExt rowExt = PXCache<TXSetup>.GetExtension<TXSetupExt>(txsetup);
Then you can access the extension fields like so:
var foo = rowExt.Usrfield;
like the title mentions I want a Query that gets a random row of the existing database. After that I want to save the data which is in a specific column of that row in a variable for further purposes.
The query I have at the moment is as follows:
#Query("SELECT * FROM data_table ORDER BY RANDOM() LIMIT 1")
fun getRandomRow()
For now I am not sure if this query even works, but how would I go about writing my function to pass a specific column of that randomly selected row to a variable?
Ty for your advice, tips and/or solutions!
Your query is almost correct; however, you should specify a return type in the function signature. For example, if the records in the data_table table are mapped using a data class called DataEntry, then the query could read as shown below (note I've also added the suspend modifier so the query must be run using a coroutine):
#Query("SELECT * FROM data_table ORDER BY RANDOM() LIMIT 1")
suspend fun getRandomRow(): DataEntry?
If your application interacts with the database via a repository and view model (as described here: https://developer.android.com/topic/libraries/architecture/livedata) then the relevant methods would be along the lines of:
DataRepository
suspend fun findRandomEntry(): DataEntry? = dataEntryDao.getRandomRow()
DataViewModel
fun getRandomRecord() = viewModelScope.launch(Dispatchers.IO) {
val entry: DataEntry? = dataRepository.findRandomEntry()
entry?.let {
// You could assign a field of the DataEntry record to a variable here
// e.g. val name = entry.name
}
}
The above code uses the view model's coroutine scope to query the database via the repository and retrieve a random DataEntry record. Providing the returning DataEntry record is not null (i.e. your database contains data) then you could assign the fields of the DataEntry object to variables in the let block of the getRandomRecord() method.
As a final point, if it's only one field that you need, you could specify this in the database query. For example, imagine the DataEntry data class has a String field called name. You could retrieve this bit of information only and ignore the other fields by restructuring your query as follows:
#Query("SELECT name FROM data_table ORDER BY RANDOM() LIMIT 1")
suspend fun getRandomRow(): String?
If you go for the above option, remember to refactor your repository and view model to expect a String instead of a DataEntry object.
Is it possible to select a single object from a group created like this?
var r = new fabric.Rect(...);
var l = new fabric.Line(...);
var roadGroup = new fabric.Group([r,l],{ ... });
So I want to have a group, but select objects l or r separately.
The simple answer is yes, but you should make sure you take into account the purpose of a group.
To get a handle on an object that is wrapped in a group you can do something like this:
var r = roadGroup._objects[0];
var l = roadGroup._objects[1];
To select a child of a group try something like this:
fabricCanvas.setActiveObject(roadGroup._objects[0]);
soapbox:
The purpose of creating a group is to treat several objects as if they were a single one. The purpose of selecting an object is to allow user interactions with an object. If you want your user to interact with a portion of a group, you might want to consider not grouping them in the first place, or else un-grouping them prior to selecting the child object.
/soapbox
I believe _objects is to be used internally only and may thus change in the future.
To me it group.item(indexOfItem) seems to be the way
So I had this scenario where I have multiple images in a box. Those all images move along with the box (as a group) but user should also be able to select an individual image and move it.
Basically I wanted to select individual objects (in my case images) of group, I did it like this:
groupImages.forEach(image => image.on('mousedown', function (e) {
var group = e.target;
if (group && group._objects) {
var thisImage = group._objects.indexOf(image);
var item = group._objects[thisImage];//.find(image);
canvas.setActiveObject(item);
}
}));
groupImages could be list of objects which you want to select individually.
I seem to be having a problem with assigning values to fields of a content item with a custom content part and the values not persisting.
I have to create the content item (OrchardServices.ContentManager.Create) first before calling the following code which modifies a field value:
var fields = contentItem.As<MyPart>().Fields;
var imageField = fields.FirstOrDefault(o => o.Name.Equals("Image"));
if (imageField != null)
{
((MediaLibraryPickerField)imageField).Ids = new int[] { imageId };
}
The above code works perfectly when against an item that already exists, but the imageId value is lost if this is done before creating it.
Please note, this is not exclusive to MediaLibraryPickerFields.
I noticed that other people have reported this aswell:
https://orchard.codeplex.com/workitem/18412
Is it simply the case that an item must be created prior to amending it's value field?
This would be a shame, as I'm assigning this fields as part of a large import process and would inhibit performance to create it and then modify the item only to update it again.
As the comments on this issue explain, you do need to call Create. I'm not sure I understand why you think that is an issue however.
I have records that have an index attribute to maintain their position in relation to each other.
I have a plugin that performs a renumbering operation on these records when the index is changed or new one created. There are specific rules that apply to items that are at the first and last position in the list.
If a new (or existing changed) item is inserted into the middle (not technically the middle...just somewhere between start and end) of the list a renumbering kicks off to make room for the record.
This renumbering process fires in a new execution pipeline...We are updating record D. When I tell record E to change (to make room for D) that of course fires the plugin on update message.
This renumbering is fine until we reach the end of the list where the plugin then gets into a loop with the first business rule that maintains the first and last record differently.
So I am trying to think of ways to pass a flag to the execution context spawned by the renumbering process so the recursion skips the boundary edge business rules if IsRenumbering == true.
My thoughts / ideas:
I have thought of using the Depth check > 1 but that isn't a reliable value as I can't explicitly turn it on or off....it may happen to work but that is not engineering a solid solution that is hoping nothing goes bump. Further a colleague far more knowledgeable than I said that when a workflow calls a plugin the depth value is off and can't be trusted.
All my variables are scoped at the execute level so as to avoid variable pollution at the class level....However if I had a dictionary object, tuple, something at the class level and one value would be the thread id and the other the flag value then perhaps my subsequent execution context could check if the same owning thread id had any values entered.
Any thoughts or other ideas on how to pass context information to a new pipeline would be greatly appreciated.
Per Nicknow sugestion I tried sharedvariables but they seem to be going out of scope...:
First time firing post op:
if (base.Stage == EXrmPluginStepStage.PostOperation)
{
...snip...
foreach (var item in RenumberSet)
{
Context.ParentContext.SharedVariables[recordrenumbering] = "googly";
Entity renumrec = new Entity("abcd") { Id = item.Id };
#region We either add or subtract indexes based upon sortdir
...snip...
renumrec["abc_indexfield"] = TmpIdx + 1;
break;
.....snip.....
#endregion
OrganizationService.Update(renumrec);
}
}
Now we come into Pre-Op of the recursion process kicked off by the above post-op OrganizationService.Update(renumrec); and it seems based upon this check the sharedvariable didn't carry over...???
if (!Context.SharedVariables.Contains(recordrenumbering))
{
//Trace.Trace("Null Set");
//Context.SharedVariables[recordrenumbering] = IsRenumbering;
Context.SharedVariables[recordrenumbering] = "Null Set";
}
throw invalidpluginexception reveals:
Sanity Checks:
Depth : 2
Entity: ...
Message: Update
Stage: PreOperation [20]
User: 065507fe-86df-e311-95fe-00155d050605
Initiating User: 065507fe-86df-e311-95fe-00155d050605
ContextEntityName: ....
ContextParentEntityName: ....
....
IsRenumbering: Null Set
What are you looking for is IExecutionContext.SharedVariables. Whatever you add here is available throughout the entire transaction. Since you'll have child pipelines you'll want to look at the ParentContext for the value. This can all get a little tricky, so be sure to do a lot of testing - I've run into many issues with SharedVariables and looping operations in Dynamics CRM.
Here is some sample (very untested) code to get you started.
public static bool GetIsRenumbering(IPluginExecutionContext pluginContext)
{
var keyName = "IsRenumbering";
var ctx = pluginContext;
while (ctx != null)
{
if (ctx.SharedVariables.Contains(keyName))
{
return (bool)ctx.SharedVariables[keyName];
}
else ctx = ctx.ParentContext;
}
return false;
}
public static void SetIsRenumbering(IPluginExecutionContext pluginContext)
{
var keyName = "IsRenumbering";
var ctx = pluginContext;
ctx.SharedVariables.Add(keyName, true);
}
A very simple solution: add a bit field to the entity called "DisableIndexRecalculation." When your first plugin runs, make sure to set that field to true for all of your updates. In the same plugin, check to see if "DisableIndexRecalculation" is set to true: if so, set it to null (by removing it from the TargetEntity entirely) and stop executing the plugin. If it is null, do your index recalculation.
Because you are immediately removing the field from the TargetEntity if it is true the value will never be persisted to the database so there will be no performance penalty.