I have a script which sends a set of records into a file. I'm using Try - Catch block to handle the exceptions. In the catch block I have a code where it has the pointer to next record. But this is not executing . Basically I wan to skip the bad record n move to next record.
while(currentrecord)
{
try
{
writerecord event
}
catch
{
currentrecord = next record
}
}
In most languages (unless you're using something very strange), If 'writerecord event' doesn't throw an exception, the catch block will not be called.
Don't you mean :
while(currentrecord) {
try { writerecord event }
catch { log error }
finally { currentrecord = next record}
}
Are you trying to loop through some records that are returned by a query? Do something like this:
var yourBusObject = TheApplication().GetBusObject("Your Business Object Name");
var yourBusComp = yourBusObject.GetBusComp("Your Business Component Name");
// activate fields that you need to access or update here
yourBusComp.ClearToQuery();
// set search specs here
yourBusComp.ExecuteQuery(ForwardOnly);
if (yourBusComp.FirstRecord()) {
do {
try {
// update the fields here
yourBusComp.WriteRecord();
} catch (e) {
// undo any changes so we can go to the next record
// If you don't do this I believe NextRecord() will implicitly save and trigger the exception again.
yourBusComp.UndoRecord();
// maybe log the error here, or just ignore it
}
} while (yourBusComp.NextRecord());
}
You can use try-finally structure so that whatever inside the finally block will always be executed, regardless of whether the code throws an exception or not. It's often used to clean up resources such as closing files or connections. Without a catch clause, any thrown exception in your try block will abort execution, jump to your finally block and run that code.
Agree that 'finally' might be the best bet here - but do we know what the exception actually is ? - can you output it in your catch loop, so that :
A) you can prove an exception is being thrown (rather than say a 'null' being returned or something)
B) Make sure the exception you get isn't something that could prevent 'nextrecord' working as well...[not sure what the 'finally' would achieve in the case - presumably the exception would have to bubble up to calling code?
So you're trying to move onto the next record if you failed to commit this one. Robert Muller had it right. To explain...
If the WriteRecord fails, then the business component will still be positioned on the dirty record. Attempting to move to the next record will make the buscomp try to write it again--because of a feature called "implicit saving".
Solution: You'll have to undo the record (UndoRecord) to abandon your failing field changes before moving onto the next one.
Related
As I write this, the documentation at https://www.npgsql.org/doc/copy.html#cancel says:
Import operations can be cancelled at any time by calling the Cancel()
method on the importer object. No data is committed to the database
before the importer is closed or disposed.
Export operations can be cancelled as well, also by calling Cancel().
I just updated my Npgsql package from 3.1.10 to 4.0.7, and now I get the error 'NpgsqlBinaryImporter' does not contain a definition for 'Cancel' for code similar to the following:
void WriteStuff(IEnumerable<RowInfo> enumerable, NpgsqlConnection conn)
{
using (var writer = conn.BeginBinaryImport("COPY blah blah FROM STDIN (FORMAT BINARY)"))
{
try
{
foreach (var rowInfo in enumerable)
{
writer.StartRow();
writer.Write(...); // blah blah
}
writer.Close();
}
catch
{
writer.Cancel();
throw;
}
}
}
It looks like this commit made Cancel() private.
So what is the correct way to cancel a bulk operation now? Do I need to wrap it in a transaction?
[And given the answer, I should just get rid of the try-catch code in the above code and just let the exception happen. Also the call to writer.Close() should change to writer.Complete(). ]
Npgsql 4.0 changed the COPY API around cancellation in a significant way, see the release notes.
In a nutshell, you must now explicitly call Complete() on NpgsqlBinaryImporter in order to commit the import; disposing it without calling Complete() will cancel the operation. This was done in order to make sure that exceptions don't cause a commit, and is aligned with how .NET TransactionScope work.
I'll update the documentation on this - thanks for pointing it out!
I'm trying without success to figure out what I'm doing wrong trying to handle one exception in my code, hopefully someone can help me.
I'm reading an external database from within Ax to integrate some customers. So I loop through a series of records using a ResultSet object. at a given point I have some code that looks like this:
while (resultSet.next())
{
//some logic (...)
ttsbegin;
//This is a custom table that stores to where I want to integrate the given customer
while select integrationCompany
where integrationCompany.CRMCompany == customerInfo.parmCRMDataAreaId()
{
changeCompany(integrationCompany.ERPCompany)
{
try
{
customerInfo.createCustomer();
//.. some more logic
}
catch
{
// My catch Block, that should update the source database to set
// the processing status to "error"
ttsAbort;
}
}
}
ttsCommit;
}
And inside the customerInfo.createCustomer() method I'm explicitly throwing some exceptions (throw Exception::Error) if some requirements aren't met.
The problem is that the catch block isn't reached - the program stops without getting back to the main routine.
Does it has something to do with the transaction opening/aborting/commiting or is something else?
AX (X++) is strange here (if you are used .NET/Java like try/catch scenario).
If you have try inside the transaction, then fist catch cathes the excation (which is Enum and not sort of exception object).
From the MSDN: Exceptions Inside Transactions:
When an exception is thrown inside a ttsBegin - ttsCommit transaction block, no catch statement inside that transaction block can process the exception. Instead, the innermost catch statements that are outside the transaction block are the first catch statements to be tested.
I am using a wcf service and I know how to catch all the exceptions I need...
But I dont know which messages should I return?
My code:
try
{
currentPosition = await locator.GetGeopositionAsync();
}
catch (FaultException<MessageError> ex)
{
MessageBox.Show(...?);
}
catch (EndpointNotFoundException ex)
{
MessageBox.Show(...?);
}
catch (CommunicationException ex)
{
...
}
catch (Exception ex)
{
...
}
I can return ex.Message but I dont want the client to know all the details, I want to show a short and helpful message.
What should I do?
I have always handled this situation in a similar way to the way that #Tim suggested in his comment. I need as much information to be saved so that I can debug the problem at a later date, but as you said, we don't want to show the end user the developer Exception messages.
Therefore the solution that I use is simply to store the information that comes from the Exception in the database and to provide the user with 'user-friendly' error messages. Make sure that you also add code to record any inner Exceptions as well if they exist. Now to address the question as to what to put in these messages... it really depends on your situation, but I generally follow this procedure.
First, I work out (either from forward thinking or from test results) which are the most likely errors to occur... off the top of my head, I'm talking about errors like 'no network access', or 'invalid user security', etc.
When I have a number of possible errors, I will attempt to catch the exact errors with a number of catch statements as you have. Inside the handlers, I check for certain Exception messages and return pre-written user friendly messages for each. Finally, I add one last generic message to display for all unforeseen error situations.
I have a situation where we update an entity data and then based on certain type of updates we may update another entity as well.
There are situations when the updation in the second entry may fail for some reasons and throw exceptions.
The question is how to handle this situation as we would like to rollback the changes done in the first entity.
We cannot defer the update to the first entry until the second entry update.
In the current situation if that happens then
as soon as the code reach the below block then it will commit the first entry changes even there are failures in 2nd entity update. so how to rollback? I think not closing the persistentManager if 2nd entity update is failed is not the right option.
finally {
try {
if (pm != null && pm.isClosed() == false )
pm.close();
} catch (Exception e) {
log.severe("Exception in finally of execute of updateDonor");
log.severe("Exception class is :" + e.getClass().getName());
log.severe("Exception is :" + e.getMessage());
throw new Exception(e.getMessage()
+ "Unable to close persistence manager");
}
log.info("end of updateDonor");
}
I'm not sure I fully understand your situation, but would cross-group (XG) transactions, which allow a transaction to be applied to entities from more than one entity group, be what you are looking for? Search for 'cross-group transactions on this page as well. With an XG transaction, either all changes to the entities encompassed by the transaction go through, or none do.
I've got a datasource that has a bunch of insert functions. Each function takes a list of items that should be inserted into the DB. Each of these items can either be successfully inserted or not. If they are not successfully inserted, I would like to know the reason why.
Are there best practices around what should be returned from a datasource insert function?
Initial thoughts:
Boolean Success: Doesn't give me any reason on failure
Custom Response Object with Boolean Success and String Reason: Can't handle >1 insert response
List of Custom Response Objects: Seems to do what I want...
If it were me, I would setup my API to throw exceptions if a row was not inserted correctly.
Would look something like (demonstrative only):
$dbo = new Database();
foreach ($items as $item) {
try {
$dbo->insert($item);
Log::toLogfile('Row was successfully inserted');
} catch (Exception $e) {
// If an exception failed upon insert, I can log the message and move on
error_log($e->getMessage());
}
}
class Database
{
public function insert(array $item) {
// Here you can add any number of validators
if (empty($item)) {
throw new Exception(sprintf('Invalid $item array (%s)', serialize($item));
}
elseif (!array_key_exists('id', $item)) {
throw new Exception(sprintf('Invalid $item[id] (%s)', serialize(item));
}
// Making a call to php function which returns bool
// No problem, we test for return value and throw exception accordingly
if (!$this->dbo->insert($item)) {
throw new Exception(sprintf('Row was not inserted (%s)', serialize($item));
}
// If we made it this far, we have successfully inserted a row
// And code resumes back up after call to this function was made
}
Throwing exceptions is the best way to get a message back to the calling code, and it forces the calling code to handle the exception. By wrapping our $dbo->insert($item) call within a try / catch block, we can catch the exception, log it, and move onto the next item in the array.
I'd return something like the # of successful inserts, and either throw an exception when one fails or emit a warning, or at least log it to a file, depending on your needs.