Consider the code below. My foo line returns data. My bar line also returns data. However, if I were to comment out the foo line, then the bar line fails to return anything. It simply crashes the app without throwing an exception. Nor does it log anything in the Event Log.
Any thoughts as to why the Async method fails - only when not preceded by the non-Async?
private async Task<bool> MyTest() {
using(var cntx = new BoomiData.PantherDataContext(pantherConnectionString)) {
try {
//var foo = cntx.Manifests.FirstOrDefault();
var bar = await cntx.Manifests.FirstOrDefaultAsync();
}
catch(Exception ex) {
Console.WriteLine(ex.ToString());
}
}
return true;
}
Related
I am using VS 2022, Blazor server project. When I trying to save data
async public static Task<bool> updateObject(Firecall obj)
{
Firecall r;
try
{
using (var context = new sptContext())
{
r = context.Firecalls.Where(c => c.Mguid == obj.Mguid).FirstOrDefault();
bool новое = (r == null);
if (новое)
{
r = new Firecall();
}
r.comment = obj.comment;
if (новое)
await context.Firecalls.AddAsync(r);
if (busy)
return false;
try
{
busy = true;
await context.SaveChangesAsync();
}
catch (Exception)
{
return false;
}
finally {
busy = false;
}
}
return true;
}
catch (Exception)
{
return false;
}
}
sometimes I get error:
Sometimes an error occurs, sometimes not. No error in debugger.
How to solve problem?
P.S. Data in each operation is saved as expected. Only after the operation is completed the indicated error message appear
And calling savechanges method from #code block of .razor view:
async private void SaveChanges()
{
bool rez = await firecallRepository.updateObject(_currentFireCall);
}
I have a logic where I need to save data in two tables(one-to-many). I have created two methods in my Java and I am trying to using Vertx Future with compose to implement the logic in sequence. But I have got half way and don't understand how to implement the compose when the first future is done. I mean code runs for the first future anAsyncAction_1(materialToAdd);, and the record is saved in the DB but now how do I call my second method in the compose
public Future<Void> anAsyncAction_2(final SendToCompanyFromSupplier rawmaterialToAdd, Integer id)
{
//code to get the id from the first future and save data in the table
}
Below is my code
public Future<Void> adddetails(final Supplier materialToAdd)
{
final Promise<Void> added = Promise.promise();
Future<Integer> fut1 = anAsyncAction_1(materialToAdd);
LOG.debug(" future.result() "+fut1.result());
fut1.compose((outcome) -> {
LOG.debug(" future.result() "+outcome);
});
CompositeFuture.all(fut1, fut2).onComplete(ar ->
{
System.out.println("BOTH OPERATION COMPLETED!! 1 " + ar.succeeded());
try
{
System.out.println("BOTH OPERATION COMPLETED!! 2 " + ar.result().list());
added.complete();
System.out.println("BOTH OPERATION COMPLETED!!");
} catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
});
return added.future();
}
If you just want to compose both the futures, the implementation can be simplified without using CompositeFuture or Promise.
Sample code:
public Future<Void> adddetails(final Object materialToAdd) {
Object rawMaterialToAdd = new Object();
return anAsyncAction_1(materialToAdd).compose(i -> anAsyncAction_2(rawMaterialToAdd, i))
.onComplete(ar -> {
if (ar.succeeded()) {
System.out.println("Both operations completed");
} else {
ar.cause()
.printStackTrace();
}
});
}
private Future<Integer> anAsyncAction_1(Object materialToAdd) {
Promise<Integer> promise = Promise.promise();
Vertx.currentContext()
.runOnContext(v -> promise.complete(1)); //Async Call. Replace with async DB call 1
return promise.future();
}
public Future<Void> anAsyncAction_2(final Object rawmaterialToAdd, Integer id) {
Promise<Void> promise = Promise.promise();
Vertx.currentContext()
.runOnContext(v -> {
System.out.println("Id received:" + id);
promise.complete();
}); //Async Call. Replace it with the async DB call 2
return promise.future();
}
Below is the sequence
Async DB call within anAsyncAction_1 will complete. The id returned will be used to complete the promise. The promise will inturn complete the first future.
The future will trigger anAsyncAction_2 with the id. Async DB call 2 on completion will complete the second future. Post the second future completion the onComplete handlers will be executed.
I have the following code, which stores information in two different tables in the same method
public static async Task<Response> AddStockTransaction(StockTransactionsHeader header, List<StockTransactionsDetails> details)
{
using (DataContext dbContext = new DataContext())
{
try
{
dbContext.StockTransactionsHeader.Add(header);
await dbContext.SaveChangesAsync();
int hearderID = header.TransactionHeaderID;
foreach (var item in details)
{
item.TransactionHeaderID = hearderID;
}
dbContext.StockTransactionsDetails.AddRange(details);
await dbContext.SaveChangesAsync();
return new Response
{
IsSuccess = true
};
}
catch (Exception ex)
{
return new Response
{
IsSuccess = false,
Message = ex.Message
};
}
}
}
How can I do, in case there is an exception in the second SaveChanges () to revert the first one?
Once SaveChanges has been called, your datat is stored on your database. You should not call SaveChanges more than once in a call, unless you are willingly to persist the intermediate steps.
You can use a transaction scope to create managed transactions :
using (TransactionScope scope = CreateTransactionScope())
{
DoSomthing(context);
scope.Complete();
}
however, if the failure of the second part involves rolling back the first one, this means that both parts belong to the same transaction, therefore simply omitting the first SaveChanges would turn your code into a single transaction.
From my another awnser: You could use DbTransaction class.
private void TestTransaction()
{
var context = new MyContext(connectionString);
using (var transaction = context.Database.BeginTransaction())
{
try
{
// do your stuff
// commit changes
transaction.Commit();
}
catch
{
// 'undo' all changes
transaction.Rollback();
}
}
}
I'm using EF Core and Devart's data provider library. I've hit an issue I can't figure out with handling user input errors smoothly. The error seems to be limited to adding a new entity to the context.
Scenario
User inputs an invalid value in a field.
Save changes is called and throws then displays error.
Prompt user to fix the error.
After this if the error is fixed and save is called again (this is good data now), I get an exception "Transaction already exists" from the Devart data provider library.
StackTrace
at Devart.Data.Oracle.OracleConnection.BeginTransaction(IsolationLevel il)
at Devart.Data.Oracle.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.Common.DbConnection.BeginTransaction(IsolationLevel isolationLevel)
at .BeginDbTransaction(IsolationLevel )
at System.Data.Common.DbConnection.BeginTransaction(IsolationLevel isolationLevel)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransactionWithNoPreconditions(IsolationLevel isolationLevel)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransaction(IsolationLevel isolationLevel)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransaction()
at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.BeginTransaction()
at
I tried to break out the transaction and handle it manually MSDN Transactions but I still get the same error.
public bool SaveAllChanges()
{
var result = false;
using (var transaction = _context.Database.BeginTransaction())
{
try
{
_context.Database.AutoTransactionsEnabled = false;
_context.SaveChanges(true);
transaction.Commit();
result = true;
}
catch (Exception exc)
{
InvokeError(exc, "Error saving changes.");
result = false;
}
}
_context.Database.AutoTransactionsEnabled = true;
_context.Database.CloseConnection();
return result;
}
How do I recover from a db error without scrapping all of the user's input? I would hate for that to be practice. I could be validating all the data going in but recovering from simple errors would be better.
After fussing around with this I found the magic sauce. This type of error only seems to come up when adding an object to the DB. It's as if the context doesn't dispose of the transaction on fail.
public bool SaveAllChanges()
{
var result = false;
_context.Database.AutoTransactionsEnabled = false;
using (var transaction = _context.Database.BeginTransaction())
{
try
{
_context.SaveChanges(true);
transaction.Commit();
result = true;
}
catch (Exception exc)
{
transaction.Rollback(); <-------- Here.
InvokeError(exc, "Error saving changes.");
result = false;
}
}
_context.Database.AutoTransactionsEnabled = true;
_context.Database.CloseConnection();
return result;
}
If someone has a solution to where I don't need to handle the transaction in this way please post it.
We cannot reproduce the "Transaction already exists" exception with the following code:
using (var _context = new MyContext())
{
var entity = new MyEntity() { ID = 10, Name = "entry exceeds max length of the field" };
_context.MyEntities.Add(entity);
try
{
_context.SaveChanges(true); // error
}
catch (Exception ex)
{
//InvokeError(exc, "Error saving changes.");
}
entity.Name = "correct input";
_context.SaveChanges(); // success
}
Please localize the issue in a small application and send us this project for reproducing.
I would like to test a method, in JUnit4, that does not pass at the first caught exception, but if all calls to the tested method throw exception. And I would like to know if this is possible.
I explain : let us say I have the method
public void setFromFen(String fenValue) throws IllegalArgumentException
in a class Position.
In PositionTest Junit4 class, I would like to do something like this :
#Test(expected=IllegalArgumentException.class){
...
setFromFen("2"); // throws IllegalArgumentException
setFromFen("8/8/8/8/8/8/8/8"); // does not throw IllegalArgumentException
...
}
so that the test only succeed if all calls to setFromFen fail.
In this case, though the second test does not throw IllegalArgumentException, the test succeed : and that's not what I want.
Is is it possible to get success only if all tests lines throws IllegalArgumentException ?
I think this is outside of the possibilities of the annotation.
You'll probably need something along these lines:
#Test
public void thatAllCallsFail() {
int failureCount = 0;
try {
setFromFen(this.sampleString1);
}
catch( final Exception e ) {
failureCount++;
}
try {
setFromFen(this.sampleString1);
}
catch( final Exception e ) {
failureCount++;
assertEquals("All 2 calls should have failed", failureCount, 2);
}
}
I'm not for a second suggesting that that is a nice way of doing it.
If you're looking for a more generic solution, perhaps adding your strings to a collection and looping over them...
#Test
public void thatAllCallsFail2() {
final String[] strings = new String[] { sampleString1, sampleString2 };
int failureCount = 0;
for (final String string : strings) {
try {
setFromFen(string);
}
catch( final Exception e ) {
failureCount++;
}
}
assertEquals("All " + strings.length + " calls should have failed", failureCount, strings.length);
}
Of course, neither of these solutions will tell you which call did not throw an exception if the tests were to fail.