How can get the error code from an Firebird Database - c#

We are using an embedded Firebird V3.0.2 for our MVC5 Project
Problem: When we update the software, we want to find out if a table exists before we create the new table. Therefor we simply make a select on the desired table and if an exception with sql error code -204 occurs, then the table does not exist. But how can I resolve the error code -204?
Code:
var lFbCommand = new FbCommand();
lFbCommand.Connection = "MyConnectionstring";
lFbCommand.Connection.Open();
// check if table exists by an select query
lFbCommand.CommandText = string.Format("SELECT FIRST 1 * FROM {0}", "MyTableName");
try
{
pFbCommand.ExecuteNonQuery();
}
catch (FirebirdSql.Data.FirebirdClient.FbException e)
{
if(e.? == -204) // -204 seem to be the errorcode for "Table does not exists."
{
// table does not exist.
}
else
{
throw;
}
}
Note: We want to prevent parsing the message text in the exception. We want to get a clear flag for this error (e.g. the error code via any property).

You shouldn't look at the (so-called) SQLcode. SQLcodes are very unspecific, for example SQLcode -204 covers a broad range of errors (maybe dozens if not hundreds of sub-errors). Not just "table unknown", but also "trigger unknown", "Datatype unknown", etc.
You'd need to look at the error code (FbException.ErrorCode) (which is not the same as the SQLcode), although that is still tricky, because sometimes error codes are nested from unspecific (covering a similar range as the associated SQLcode) to more specific. And that is the case for "table unknown" (isc_dsql_relation_err or 335544580), which is nested in the group isc_dsql_error (335544569). The isc_dsql_error - IIRC - maps almost one-to-one to SQLcode -204 (which could be a few dozen to a few hundred errors).
As far as I know - but I don't usually program in C# - you will need to look at FbException.Errors (which returns a FbErrorCollection) and check if it contains the right error(s).

Related

2 errors when trying to use RFCDestination.Repository.GetTableMetadata(string tablename)

I know that you can get the data of a table in a SAP Server with the function RFCDestination.Repository.GetTableMetadata(string tablename). Unfortunately I get an error when I try to execute the command. The weird thing is when I give a exisiting table I get a different error when I try something random as a tablename.
Existing table:
var x = dest.Repository.GetTableMetadata("TFTIT");
Error:
SAP.Middleware.Connector.RfcInvalidStateException: "cannot find TABLE specified by TFTIT"
Random tablename:
var x = dest.Repository.GetTableMetadata("Test123");
Error:
SAP.Middleware.Connector.RfcInvalidStateException: "metadata for TableOnly TEST123 not available: NOT_FOUND: No active nametab exists for TEST123"
I know there is a way to get the data of a table with the help of a function module but I need to use the GetTableMetadata function.
One cannot do so much wrong when calling RfcRepository.GetTableMetadata(string). Does your used user ID has the required RFC authorizations for repository queries as listed in SAP note 460089 (scenario 3)? If yes, this is maybe a bug in the NCo3 library or even in the ABAP backend. Do you use NCo's latest patch level? This is currently NCo 3.0.20.
If not, try updating the library first.
Otherwise I recommend to create an SAP support ticket for the first error message. The second error is normal when the specified table name does not exist.
Alternatively you may also try what happens if calling RfcRepository.GetStructureMetadata(string) for this table instead. The meta data for tables and structures is quite similar and the same remote function modules are used for the DDIC queries. Maybe this works. However, I think in the first place RfcRepository.GetTableMetadata(string) should work here.
I hope this helps.

C# System.Data.SQLite : Concurrency violation: the UpdateCommand affected 0 of the expected 1 records

I have a .net winforms application which is using SQLite DB and I am using System.Data.SQLite dll.
This is how I load a Datatable:
DataTable table = new DataTable();
SQLiteDataAdapter m_readingsDataTableDataAdapter;
SQLiteCommandBuilder m_readingsDataTableCommandBuilder;
m_readingsDataTableCommandBuilder = null;
m_readingsDataTableDataAdapter = null;
// Create fresh objects
m_readingsDataTableDataAdapter = new SQLiteDataAdapter(sql, Database.getInstance().connectionObj);
m_readingsDataTableCommandBuilder = new SQLiteCommandBuilder(m_readingsDataTableDataAdapter);
m_readingsDataTableDataAdapter.Fill(table);
return table;
This data table has one primary key and no other constraints.
I set it as a data source for DataGridView and after all the edits, I update the DataTable like this:
m_readingsDataTableDataAdapter.Update(table);
Occasionally, the updates fires an error and I don't know when, it stops throwing errors - probably after system restart ( not sure ). And then, the updates go fine until another situation where this update throws an error again. When the error occurs, it happens for all updates from then on even after application restart.
Error:
An unhandled exception of type 'System.Data.DBConcurrencyException' occurred in System.Data.dll
Additional information: Concurrency violation: the UpdateCommand affected 0 of the expected 1 records.
I would appreciate any help or questions as this is quite a critical section of my project.
Thanks.
Update:
Based on suggestions, to ensure no other part of the program is editing the row, I loaded the DataTable, updated the row immediately and updated it as per the following code. And I still got the error. There is no other program running on my machine so the row is not updated by any other program except my application:
DataTable table = new DataTable();
SQLiteDataAdapter m_readingsDataTableDataAdapter;
SQLiteCommandBuilder m_readingsDataTableCommandBuilder;
m_readingsDataTableCommandBuilder = null;
m_readingsDataTableDataAdapter = null;
// Create fresh objects
m_readingsDataTableDataAdapter = new SQLiteDataAdapter(sql, Database.getInstance().connectionObj);
m_readingsDataTableCommandBuilder = new SQLiteCommandBuilder(m_readingsDataTableDataAdapter);
m_readingsDataTableDataAdapter.Fill(table);
// Update immediately
table.Rows[0]["RS485_ADDRESS"] = "400";
m_readingsDataTableDataAdapter.Update(table); // - Still throws error
return table;
I had a similar issue that drove me nearly mad. I even debugged into System.Data.SQLite . My issue was caused by the dynamic typing of SQLite:
Dynamic typing means that the column type is just a hint for the type of the stored value but not an enforcement. Here is what happened in my application: An integer column contained an empty string. Fetching the data triggered an implicit conversion to the column type so the empty string was converted to zero. The DbDataAdapter used this zero value in the WHERE clause of an UPDATE or DELETE statement which failed miserably because the conversion of zero to a string is not an empty string. I changed the affected integer columns to contain NULL and everything is fine now.
The sad fact about that: It is not a bug in SQLite or ADO.NET . DbAdapter and DbCommandBuilder expect strong typing and SQLite doesn't provide that by design.
I've seen this problem, it seemed to appear in some cases and not others. I have resolved it a different way. Since this is primarily a data issue, it involves changing the update and delete statements. There may be cases where your code might need to be validated, I'm not referring to those cases, this is for when all else seem to be in order and "Concurrency Violation" persists. And a good starting place before you spend hours debugging is to address how the updates are handled.
Open the Data Set Designer.
Click on the Table Adapter.
In the properties, expand the UpdateCommand
Edit the SQL so the Where-Clause refers only to the primary-key.
Example: Suppose the column EmployeeID is the primary-key in our table
Change to:
update ..... WHERE EmployeeID=#EmployeeID
By default it's usually constructed as:
update ... where ID=#ID AND col1=#col1 AND col2=#col2 AND col3=#col3
The where-clause is formed with all the columns to handle multi-user updates, to enforce an implicit concurrency. So if one user has a copy of the record, and another user updates that version by the time the first user updates it, first user's version is not current. Otherwise, primary-keys should be used to refer to a specific record.
But, this is an update/delete policy decision that the development and database teams need to coordinate. For a single developer/dba in-one, have a little meeting with yourself. Don't take the Microsoft where-clause without your review and understanding and explicit implementation. Need to specifically address what happens when 2 users have a copy of the same record, both from the application and database levels. Database "Transaction Isolation" Levels in SQL Server is a way to address it. ADO, ADO.NET, OLE DB, ODBC all have isolation level settings. More on SQL Server Transactions and isolation levels
In some cases multiple users are not involved, or the application is updating internally, concurrency is fully controlled, where-clause can be formed with the primary-key.
In my case, the update is done without a user involvement, so it makes sense to use the primary key. If you understand the reasoning and the cause of the behavior, it's a matter of adjusting to fit your environment.

Getting Data from Access DB to appear in TreeView results in IndexOutOfRange exception

I have a TreeView, and am using a DataReader to populate it with data from specific columns in the database, specifically "consultationDate" (and another one beginning with the same name, just append "Notes" onto the end of that one, to get "consultationNotes).
The thing is, as soon as it gets around to executing the code that is meant to add the notes to the tree view, it tell me that I have an IndexOutOfBoundsException. The columns concerned do have data in them.
The code is below.
Any ideas as to why I am getting that error?
while (treeNodeReader.Read())
{
//childNode = parentNode.Nodes.Add("Note Details: " + treeNodeReader["consultationNotes"].ToString());
}
(For ease of readability, because the issues is the same for both columns, I've included only one column's code here).

Batch inserts using ContinueOnError

I'm using the following code to do a batch insert using the C# driver. I have a unique index, and I want it to fail silently if I try to insert a record that isn't unique.
Even though I have InsertFlags.ContinueOnError set, I still get an error on the InsertBatch call. If I swallow the error as I have shown below, everything works ok. But this certainly feels wrong.
var mio = new MongoInsertOptions {Flags = InsertFlags.ContinueOnError};
// newImages is a list of POCO objects
try
{
_db.GetCollection("Images").InsertBatch(newImages, mio);
}
catch (WriteConcernException)
{
}
Are you using version 1.8 of the csharp Mongo driver?
If so, try upgrading to version 1.8.1 which contains a fix for the following two issues:
InsertBatch fails when large batch has to be split into smaller sub batches
InsertBatch throws duplicate key exception with too much data...
So your inserts could succeed, but the driver is still throwing an exception on bulk insert operations due to the bug above.
And this exception doesn't originate from the database itself, explaining why the inserts succeed but you still need to catch the exception afterwards - i.e. the db is in fact respecting your ContinueOnError flag but the driver throws an exception anyway afterwards.

Row not found or changed LINQ C# error on simple statement

First of all, there is no chance that this is a multi-user issue, as I'm working locally on a dev version of the database.
I am getting the not very explanatory Row not found or changed error being thrown when I perform db.SubmitChanges(). If I break the execution just before the SubmitChanges() occurs, I can check in SQL Server Management Studio and the row does exist!
Here's the code for the whole function, just to put it in context for anyone who wants to help, but the problem line is right at the end (line 48).
Update This is a really odd one: the error is caused by updating matchingTrans.Url (see penultimate line of code). Commenting out this line doesn't throw the error - even if the matchingTrans.Title still gets updated.
private static void MenuItemUpdate(int languageId, NavigationItem item)
{
using (var db = DataContextFactory.Create<MyDataContext>())
{
// Select existing menu item from database.
var dbItem =
(from i in db.MenuItems
where i.Id == item.Id
select i).Single();
// Obtain ID of link type.
dbItem.FkLinkTypeId = GetLinkTypeByName(
Enum.GetName(typeof (NavigationItemLinkType), item.LinkType)).Id;
// Update the Link field with what is given.
dbItem.Link = item.Link;
db.SubmitChanges();
// Item already exists and needs editing.
// Get associated translations.
var trans =
from t in db.MenuItemTranslations
where t.FkMenuItemId == item.Id
select t;
// If translation exists for given language, edit it.
var matchingTrans =
(from t in trans
where t.FkLanguageId == languageId
select t).SingleOrDefault();
if (matchingTrans == null)
{
// No matching translation - add one.
var newDbTrans = new MenuItemTranslation
{
FkMenuItemId = item.Id,
FkLanguageId = languageId,
Title = item.Title,
Url = item.FriendlyUrl
};
db.MenuItemTranslations.InsertOnSubmit(newDbTrans);
db.SubmitChanges();
}
else
{
// Matching translation - edit it.
matchingTrans.Title = item.Title;
matchingTrans.Url = item.FriendlyUrl;
db.SubmitChanges();
// WTF ERROR: Row not found or changed.
}
}
}
Looking at the SQL Profiler output, it helped me figure out the answer to this. There was a bad piece of SQL being generated which ended with WHERE 0 = 1 ... an obvious error.
It turns out that the field had simply been changed to allow nulls by another developer, and the Linq-to-SQL file hadn't been updated accordingly.
In short, if the Row not found or changed error message appears to be generated for no reason, make sure your database schema exactly matches your .dbml file else you'll get this error message on any fields that have slightly differing schemas.
Take a look at the connection property "No Count" at sql server server level
1. Right click on Sql server connection in Object Explorer -->Property
2. Go to Connection Tab/Page
3. Look for the Default connection option "no count"
4. Make sure this option is not checked.
Another possibility that I've found to add to the excellent list of answers here:
When using a not-nullable column in a database - then mapping that to a datatype that is intrinsically nullable (in this example DB type is LONG BLOB NOT NULL mapped to a byte array in c#) you can end up in a situation where updating the database with the exact same byte array causes this error to be thrown.
Example: You have a website that allows the user to upload an image to the database. Your table has a blob (image in sql server, whatever) that is not nullable. The user chooses to update the record with the exact same image that is already there. The update check will fail. I fixed this by first doing a .SequenceEqual() check and then only calling .SubmitChanges() on the context object if the incoming byte array was not equal to the existing one.
I had this issue even when the database schema and dbml matched exactly. The issue was I was trying to change an entity and insert entities in a single SubmitChanges statement. I fixed it by doing SubmitChanges on each operation instead of all at once.
This was all in a transaction scope so that may have something to do with it but I'm not sure.

Categories

Resources