I have this error when I try to add a line of package
Error : Another process has added the "SOPackagedetail" record. Your changes will be lost.
error
My c# code is this :
protected virtual void creationColis()
{
SOShipment ship=Base.CurrentDocument.Select();
SOPackageDetailEx colis = new SOPackageDetailEx();
colis.BoxID="COLIS";
colis.PackageType="M";
colis.ShipmentNbr=ship.ShipmentNbr;
SOShipmentEntry graph = PXGraph.CreateInstance<SOShipmentEntry>();
graph.Packages.Insert(colis); //insertion de l'enregistrement
graph.Packages.Update(colis);
graph.Actions.PressSave();
graph.Clear();
}
Do you know what I must to change please ?
Thanks so much
Xavier
Your question needs more context. For starters, where does your code reside? Given that you reference Base.CurrentDocument.Select, I'm going to assume you are extending SOShipmentEntry to add your code.
In this case, you would just use the Base.Packages view rather than initializing your own instance of SOShipmentEntry where your example goes into trying to use graph.Packages. Regardless, there are 2 parts here that need to be addressed.
Packages is not the primary view of SOShipmentEntry. When you create an instance of a graph, you must tell the graph what record is needed in the primary view. In your example where you create a new instance of a graph, you might do something like this:
graph.Document.Current = graph.Document.Search<SOShipment.shipmentNbr>(myShipmentNbr);
If you are working on a graph extension of SOShipmentEntry, then you probably don't need to create a new instance of the graph. Just make sure graph.Document.Current isn't null before you add your package record - see bullet 2.
Once you have a shipment selected, you can then insert your package information. However, the way you have done it here effectively is trying to add a random package to a null shipment (by the structure of the views) but forcing the record to attach to the right shipment by sheer brute force. The views don't like to work that way.
A better way to add your package once you have a current shipment (Document) is like this:
// Find the current shipment (from the primary view Document)
SOShipment ship = Base.Document.Current();
if(ship?.ShipmentNbr != null) {
// Insert a record into the Packages view of the current shipment and return the record into colis
SOPackageDetailEx colis = Base.Packages.Insert(colis);
// Set the custom values
colis.BoxID="COLIS";
colis.PackageType="M";
// Update the Packages cache with the modified fields
Base.Packages.Update(colis);
// If more fields need to be updated after those changes were applied, instead do this...
colis = Base.Packages.Update(colis);
colis.FieldA = ValueA;
colis.FieldB = ValueB;
Base.Packages.Update(colis);
// If a save is needed, now is the time
Base.Save.Press();
}
Notice that I didn't assign ShipmentNbr. That is because the DAC has that field defined to pull the ShipmentNbr from SOShipment through these 2 attributes.
[PXParent(typeof(FK.Shipment))]
[PXDBDefault(typeof(SOShipment.shipmentNbr))]
This means that when the record is created, Acumatica should lookup the parent SOShipment record via the Key and do a DBDefault on the field to assign it to the SOShipment.ShipmentNbr value (from the parent). Important side note: PXDefault and PXDBDefault are NOT interchangeable. We use PXDefault a lot, but off the top of my head I can't think of a case of PXDBDefault outside of defaulting from a database value like this specific usage.
Related
I am creating a web API. I need something like this:
When I updating a document at mongodb, I do not want to update a field (createdAt). I know that I can get a old value of that field and manuelly and then put it updated object but it requires one more unnecessarry request to db. I do not want this. My method is here:
public async Task<bool> UpdateAsync(Customer updatedCustomer)
{
var result = await _mongoService.Customers.ReplaceOneAsync(c => c.Id == updatedCustomer.Id, updatedCustomer);
return result.IsModifiedCountAvailable && result.ModifiedCount>0;
}
Is there any way to exclude one property of my Customer class (createdAt) and left it same everytime. BTW please do not recomend that set all properties update one by one by using "Set" method. Thank you.
I'm not sure if there is a way other than to set the properties one by one, but researching the following may be helpful or suggestive of something new.
In Mongodb you can use some decoration to do like [BsonIgnore] but it will ignore it every time
One alternative would be to load the document you wish to modify, followed by calling BsonDocument.Merge with overwriteExistingElements set to true in order to merge your changes.
The Issue
I am trying to create an endpoint for my API that will take a list of DTOs and update each of them.
What I've Tried
In my first attempt, I made a method with the HttpPatch attribute that took a list of the given DTO as its parameter, and the DTOs were correctly filled with the data I sent (and had null/default values for any of the fields I didn't send). However, this leaves me with the issue of not knowing what values have been actually changed since this way I cannot tell the difference between a field I want changed to null and a field that is not being updated.
Thus, in my second attempt I used a list of Delta of the given DTO, using Delta class. This allowed me to discern which fields were being changed in the DTOs provided- however, it inexplicably no longer includes the primary ID key, so it is impossible to update my data with the changed information I have now isolated.
References
Below is a paraphrased example of my code and a link to the Delta class documentation. Please let me know if there is anything I can clarify, and thanks in advance for your help!
Code Example
[HttpPatch]
[Route(".../UpdateMany")]
public HttpResponseMessage UpdateMany(List<Delta<Dto>> deltaDtos) // My first implementation had 'List<Dto> dtos' as the parameter
{
var dtos = new List<Dto>();
var changesList = new List<KeyValuePair<Guid, List<string>>>();
foreach (Delta<Dto> dto in deltaDtos) // This for loop extracts the DTOs from the Deltas and makes a list of lists of changes keyed to their respective DTO ID.
{
var updatedProperties = dto.GetChangedPropertyNames().ToList(); // The updated properties contains a list of the changed field(s), but does not include the ID.
changesList.Add(new KeyValuePair<Guid, List<string>>(dto.GetEntity().ID, updatedProperties));
dtos.Add(dto.GetEntity()); // dto.GetEntity() returns an instance of Dto with the changed fields filled out- not including the ID field for some reason, but including the changed field(s).
}
_service.UpdateMany(dtos, changesList); // The service handles the updating logic.
return Request.CreateResponse(HttpStatusCode.OK);
}
System.Web.Http.OData.Delta Documentation
https://learn.microsoft.com/en-us/previous-versions/aspnet/jj890572(v=vs.118)
I am trying to import cases from our old ticketing system into Acumatica using a C# console application. I have the old tickets loaded, and I am trying to use the REST API to create the cases.
I created a custom web service endpoint to load the cases, but I would also like to create message activities from the posts in our old system. If I use the Cases screen under Organization, I can add a Detail entity for activities. However, there does not appear to be a way to add the Activity Details field, which is the body of the activity. Here is a screenshot of the current endpoint setup showing the top-level Case entity I created:
The above image shows the Case entity, which does not appear to have the ActivityDetails field. However, if I use the Activity screen from the Hidden site map folder, the ActivityDetails is present. Here is a screenshot of the Activity entity I created, which does have ActivityDetails:
I hope this makes sense, but I would like the ActivityDetails field to be available from the Cases top-level entity so I can insert a complete case including activities and their detail. Any help would be greatly appreciated.
Thank you.
This is not a behavior that is possible.
The reason for this is that when you go on that screen using the UI, there is no possibility to add new Event, Task or Activity directly from that screen. The action button that are there only serve as to open the other screens a already create a link to the case from where the action was clicked on.
Since the APIs work by dealing with one screen at the time, it is not possible from the Case screen to create an Activity.
So to create an Activity for a Case, you will first have to create the Activity and then link it to the Case.
In order to do so, you must first add some field to both the Case entity and the Activity Entity.
These fields must be added manually as they are not part of the autocompletion.
For the Case entity, you need to add the following field:
Field Name = "NoteID"
Mapped Object = "Case Summary"
Mapped Field = "NoteID"
Field Value = "GuidValue"
enter code here
For the Activity entity please add the following field:enter code here
Field Name = "RefNoteID"
Mapped Object = "Activities"
Mapped Field = "RefNoteID"
Field Value = "GuidValue"
Once these two fields have been added, you can start adding the activity to the case.
In order to do so:
1) Retrieve the Case on which you want to add the activity using A GET call. You will need to use the value from the NoteID field that has just been added.
2) Create the Activity like you normally would, using a PUT call, but instead of trying to add a value in the RelatedEntityDescription field, add the NoteID value you just retrieved from the Case to the RefNoteID field you just added to the Activity entity. In the response you will be able to see that the Activity was linked to the case by checking the RelatedEntityDescription field.
I have added a LinkField called Website to a content type using a part with the same name as the content type.
ContentDefinitionManager.AlterTypeDefinition("MyContentType", a => a
.WithPart("CommonPart")
.WithPart("MyContentType")
.Creatable());
ContentDefinitionManager.AlterPartDefinition("MyContentType", cft => cft
.WithField("Website", a => a.OfType("LinkField").WithDisplayName("Website")
.WithSetting("FieldIndexing.Included", "True"))
.Attachable());
I then create some default content items during the migration.
I'm creating the item before adding the field data because I have had problems with fields not being updated when their values are set before the item is created. (Feel free to shine some light on that, but that isn't my question though)
var myItem = _orchardServices.ContentManager.New("MyContentType");
_orchardServices.ContentManager.Create(myItem);
var websitePart = myItem.Parts.FirstOrDefault(x => x.Fields.Any(y => y.Name == "Website"));
var websiteLinkField = websitePart .Fields.FirstOrDefault(x => x.Name == "Website") as LinkField;
websiteLinkField.Value = "http://www.google.com";
websiteLinkField.Text = "Link to google";
_orchardServices.ContentManager.Publish(myItem);
I realize there are more dynamic ways to access the field, but this seems to work too.
The data shows up when I view the items, but then I move on to making a Query.
I use the UI to build a simple query looking for the word "google" in the text of the LinkField, then I hit preview.
No results are found.
I then open up one of the items created from the migration and simply hit the "Save" button.
Then I try the preview again and the item I saved now shows up.
So as far as I can tell something is happening when I save a content item that I'm not doing from the migration. But I have been stepping through the code going over all angles, and I just can't find it.
I suspect maybe some handler is supposed to get triggered in order to create the FieldIndex'es ?
(I know how to trigger an update for the Lucene index, but as one would expect it does not affect querying fields using the Projections module and I'm really lost at this point.)
By now I'm just stabbing blindly in the dark.
Would really appreciate any help I can get, even if it's just something pointing me back in the right direction. Thank you.
You should change
_orchardServices.ContentManager.Create(myItem);
to
_orchardServices.ContentManager.Create(myItem, Orchard.ContentManagement.VersionOptions.Draft);
For understanding look at CreatePOST method of Orchard.Core.Contents.Controllers.AdminController class and Publish method of Orchard.ContentManagement.DefaultContentManager class
In your case when you call a Create(myItem) then created published content item and all handlers are invoked normally (but has not yet set up a desired data). When you call Publish(myItem) nothing happens (no handlers are invoked) because your content is already published.
I've raised this as a bug, vote for it if you think it needs fixed.
#Alexander Petryakov is correct in his description of what is happening and his work around is probably the correct approach, however the behaviour doesn't make sense, which is why I have raised the bug. The code in your question manages to create an inconsistency between the content view of the data, stored in the Orchard_Framework_ContentItemVersionRecord table and the Projections view of the data stored in the Orchard_Projections_StringFieldIndexRecord table. Essentially, the Orchard_Projections_StringFieldIndexRecord contains null because it hasn't processed the publish event after you updated the field.
The code you have essentially does the following things:
Create a content item + publish it's creation
Update one of the content items fields this update doesn't change the state of the content
Try to publish the content item which doesn't do anything because it thinks it is already published.
To me, if you update a field on the content item, then the state of the item you are working on should no longer be published (it's changed since you published it). The Fields provide hooks that allow you to be notified when they are updated, so an alternate way of solving the problem would be to create a class that implements the interface IFieldStorageEvents that updates the published state of the content when a field is updated.
public class FieldUpdateEventHandler : IFieldStorageEvents {
public void SetCalled(FieldStorageEventContext context) {
context.Content.ContentItem.VersionRecord.Published = false;
}
}
This would allow your original code to run as it was written.
I am experiencing this exception when trying to define a data member contained within another piece of data.
Example:
Container newRecord = this.DataWorkspace.ApplicationData.Containers.AddNew();
newRecord.SubContainer = this.DataWorkspace.ApplicationData.SubContainers.AddNew();
The exception, "Reference properties cannot be set to deleted or discarded entities.", is encountered with the second line.
I don't understand what entity it's talking about with regard to it being discarded or deleted, so any help with this issue would be most appreciated.
The code lines are in an interface function defined in LightSwitch, which is called from a Silverlight project, passing data from that project to the LightSwitch project.
I eventually managed to do this after working out that I needed to be on the 'Logic' thread, which I was not. I spent a little while messing around trying to find a this.DataContext but could not (my Silverlight project had this but not the LightSwitch project).
Eventually though I found out what I needed to do:
this.Details.Dispatcher.BeginInvoke(() =>
{
Container newRecord = this.DataWorkspace.ApplicationData.Containers.AddNew();
newRecord.SubContainer = this.DataWorkspace.ApplicationData.SubContainers.AddNew();
newRecord.exampleIntProperty=2;
newRecord.SubContainer.innerString="Example";
});
I can then assign data to the properties of newRecord and the properties of the objects it contains (such as the example SubContainer's properties), although obviously the new record is not saved until LightSwitch is instructed to save its data.
Your code needs to be changed slightly:
Container newRecord = this.DataWorkspace.ApplicationData.Containers.AddNew();
SubContainer newSub = newRecord.SubContainers.AddNew();
If the navigation property isn't called SubContainers, just replace that with the correct name.