Comparing RPG to C# and SQL - c#

In an RPG program (One of IBM's languages on the AS/400) I can "chain" out to a file to see if a record (say, a certain customer record) exists in the file. If it does, then I can update that record instantly with new data. If the record doesn't exist, I can write a new record. The code would look like this:
Customer Chain CustFile 71 ;turn on indicator 71 if not found
if *in71 ;if 71 is "on"
eval CustID = Customer;
eval CustCredit = 10000;
write CustRecord
else ;71 not on, record found.
CustCredit = 10000;
update CustRecord
endif
Not being real familiar with SQL/C#, I'm wondering if there is a way to do a random retrieval from a file (which is what "chain" does in RPG). Basically I want to see if a record exists. If it does, update the record with some new information. If it does not, then I want to write a new record. I'm sure it's possible, but not quite sure how to go about doing it. Any advice would be greatly appreciated.

RPG has intrinsic connectivity to the database tables on the system. That makes it easy to write such succinct operations.
C#, on the other hand, requires you to implement your own database routines (or use a framework like LINQ).
If I was doing this, I would create a class responsible for database manipulation using the System.OLEDB objects.
Some methods might be (general idea, not actual code):
public boolean CheckExists(string TableName, string ColumnName, int ID) {
//Connect to database
// Create Command with query "SELECT COUNT(1) FROM " + TableName.Replace(";","") + " WHERE " + ColumnName.Replace(";","") + " = " + ID
Return int.Parse(myQuery.ExecuteScalar) > 0
//disconnect
}
public boolean UpdateCredit(int CustID, int newCredit) {
//Connect to database
// Create Command with query "UPDATE CustTable SET CustCredit = " + newCredit.ToString() + " WHERE = CustId = " + CustID
myQuery.ExecuteNonQuery
//disconnect
}
public boolean CreateCredit(int CustID, int newCredit) {
//Connect to database
// Create Command with query "INSERT INTO CustTable (CustID, CustCredit) VALUES (" + CustId.ToString + ", " + newCredit.ToString + ")"
myQuery.ExecuteNonQuery
//disconnect
}
Then your main method world read something like
If (CheckExists("CustTable", "CustId", CustID)) {
UpdateCredit(CustID, 10000)
} else {
CreateCredit(CustId, 10000)
}

Related

Get 2 or more different informations from a SQL-database (from different tables)

Im trying to get different informations from different tables with 1 SQL-connection.
The actual code is:
sql_Verbindung.MssqlCommand.CommandText = "SELECT USER, PWD FROM " + server + ".[dbo].[table1] where USER = '12345'";
sql_Verbindung.OpenConnection();
sql_Verbindung.MssqlReader = sql_Verbindung.MssqlCommand.ExecuteReader();
if (sql_Verbindung.MssqlReader.HasRows)
{
while (sql_Verbindung.MssqlReader.Read())
{
object.Name = sql_Verbindung.MssqlReader["USER"].ToString().Trim();
object.Passwort = sql_Verbindung.MssqlReader["PWD"].ToString().Trim();
}
}
sql_Verbindung.CloseConnection();
sql_Verbindung.MssqlCommand.CommandText = "SELECT * FROM " + server + ".[dbo].[table2]";
sql_Verbindung.OpenConnection();
sql_Verbindung.MssqlReader = sql_Verbindung.MssqlCommand.ExecuteReader();
while (sql_Verbindung.MssqlReader.Read())
{
if (sql_Verbindung.MssqlReader["Live"].ToString() == "1")
{
object.database_available = true;
}
else
{
object.database_available = false;
}
}
sql_Verbindung.CloseConnection();
This works but I think it could be a lot better.
(The SQL.open and SQL.close obviously open and close the connection.)
And how can I get both informations without closing the conenction in between? If I try using the same code without closing the connection it crashes.
Thank you in advance!
If your requirement is to get resultset of two table from the same database why don't you use Union.
SELECT USER, PWD, NULL AS LIVE FROM " + server + ".[dbo].[table1] where USER = '12345'
UNION ALL
SELECT NULL AS USER, NULL AS PWD, Live FROM " + server + ".[dbo].[table2]
Improvement area.
Use store-procedures if possible to avoid sql injection.
If still you want to use inline query then try to use query like mentioned above, instead making multiple round trips to database.

How do I make my query more precise based on my condition to return a string to check duplicate record exist

I am creating string function which checks duplicate record before inserting or updating a record but I have a condition with it. Before giving conditions, I have a table called Products (name, description, type, isActive, InsertedDate, UpdatedDate). Isenabled is in bit datatype (0 or 1). And InsertedDate, UpdatedDate are auto generated.
In isActive column
0 means disable
1 means enable
Before inserting (or even updating), check whether name is unique but if name exist more than one then,
My conditions
Check whether product is isActive = 1 then while inserting data should display message "Product exist in the table."
Check whether product is isActive = 0 then while inserting data should display message "Product exist but it is disabled."
Else Insert/Update the data.
Below function only check whether record exist or not and return message accordingly.
Question: How can I have return proper message regardless I am checking above query for inserting or updating a record and it goes over my requirement. As Top 1 can help me to insert new record checking if name is unique and it will return empty but if I am updating row with its own keeping name as it is and changing other column which is description. And when I update that I am receiving message "Record exist in the table" which it should not give me and should updating without message. So how can I make this query check for both the method inserting and updating record.
Here is what I have tried:
private string GetName(string name, int id)
{
using (var connection = connection string)
using (var command = new SqlCommand())
{
command.Connection = connection;
command.CommandText =
#"DECLARE #Enabled INT; " +
#"SET #Enabled = " +
#"( " +
#"SELECT TOP 2 p.isActive " +
#"FROM dbo.[product] p WITH (nolock) " +
#"WHERE p.name = #name " +
#"); " +
#"SELECT Msg = CONVERT( VARCHAR(32), " +
#"CASE " +
#"WHEN #Enabled = 0 " +
#"THEN 'Record is disabled' " +
#"WHEN #Enabled = 2 " +
#"THEN 'Record exist in the table' " +
#"ELSE ''";
#"END);";
command.Parameters.AddWithValue("name", name);
command.CommandTimeout = 100;
connection.Open();
command.ExecuteNonQuery();
string message = (string)command.ExecuteScalar();
connection.Close();
return message;
}
}
return string.Empty;
}
Note My query might be wrong. If you do not understand my query then please go over to what I am doing before inserting or updating record and accordingly I am expecting to have a query. Also please don't worry about Insert or update query I have a different method which takes care of it. Also if you have any solution which can help me to solve my probkem ten I would really appreciate that.
Summery
First check duplicate record exist or not (Means check all names are unique).
If name exist more than 1 then check isActive is 0 or 1 and accordingly sends the message which I am showing in my query.
FYI: I know I can do it in Stored Procedure but this is like a requirement to do it with command parameter.
Also if you guys think tha this post does not have consistant, please let me know instead of downgrading or flagging it.

Duplicate key on mysql

I have a POS system that will be used to create receipts in two different locations. the problem i am having right now is that when both location enter a receipt at the same time, they would have the same receipt ID, and therefore, i made a pretty bad way to fix this problem.
while (!success)
{
try
{
MySqlCommand myCommand4 = new MySqlCommand("Insert into OrderRecords_table values('" + OrderID + "','" + customerCode + "','" + customer + "','" + TelComboBox.Text + "','" + LicenseComboBox.Text + "','" +
DriverComboBox.Text + "','" + AddressComboBox.Text + "','" + LocationTypeComboBox.Text + "','" + PickupComboBox.Text + "','" + CustomerTypeLabel.Text + "','" +
Convert.ToDecimal(TotalPriceLabel.Text) + "','" + status + "','" + note + "','" + sandReceiptNo + "','" + createtiming + "','" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "')", myConnection52);
myCommand4.ExecuteNonQuery();
if (retried == true)
{
MessageBox.Show("收據號碼已改為: " + OrderID);
}
success = true;
}
catch (MySqlException ex)
{
switch (ex.Number)
{
case 1062:
retried = true;
OrderID = OrderID.Substring(0, 1) + (Convert.ToInt32(OrderID.Substring(1, OrderID.Length - 1)) + 1).ToString("00000");
success = false;
break;
}
}
}
i have wrote this to catch the exception, and increase the receipt number when that duplicate key happens, and it worked fine when i first test it, however, it is won't catch the exception anymore, and it would just insert the record.
I don't know how it breaks the rules on mysql.
the situation right now is like the following:
if i have a record with receipt number: m00001 (orderID col)
and the other program is trying to insert a receipt number that is also m00001, it should catch that exception, but it insert both m00001 somehow. (orderID column is set as primary key).
i was doing some researches online to see if there is another way to fix this problem, and i found this
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
however, this update the old record instead of the new one, is there another way that would update the one that i am trying to insert if it is found duplicated?
Thanks
Classic concurrency control problem. Modern relational databases handle this problem by having the database generate the ID. Internally, the database utilizes a mutex to ensure that only one thread is ever able to increment the counter at once. This is usually exposed in SQL via sequences or a special data type that wraps up the functionality. In MySQL, there is a special data type called SERIAL that will handle the IDs automatically using MySQL's internal sequence generator called AUTO_INCREMENT.
Otherwise, you will have to implement locking and concurrency control yourself. I do not recommend doing this, since MySQL can do it better and faster than you could, but it is possible.
Changing an existing column to begin using AUTO_INCREMENT is a trivial operation that can be quickly done against smaller data sets (less than a million rows or so). Let's say you have a table that looks like this:
mysql> SHOW CREATE TABLE t_receipts;
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t_receipts | CREATE TABLE `t_receipts` (
`id` bigint(20) unsigned NOT NULL,
`amount` double(8,2) DEFAULT NULL,
`date_created` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
Converting the table is as simple as:
ALTER TABLE t_receipts CHANGE id id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT;
Or, using the SERIAL shortcut:
ALTER TABLE t_receipts CHANGE id id SERIAL;
visual studio has a great tool called entity framework for .net, there is a guide to use it with MySQL. It will make everything a lot safer and easier, it would suggest you use this.
Using the entity Framework and Linq if there is a problem, like a duplicate key it will always throw an exception. Creating keys if you cannot use auto increment or a GUID is a bit easier because of the exceptions, you will always know when the key you tried to insert is wrong.
A table in your database will just be a class in C# with the entity model, you simply create a new object of this class fill in the field, add it to the collection (which corresponds to the records in your database) and save. on save it will check if it is original and the record will be created.
For as far as I know this will never allow for a duplicate key no matter how many connections and how simultaneous the records are added.
example code for adding with linq to your entity model:
MyDbEntities mydb = new MyDbEntities();
Order order = new Order();
order.OrderID = "m0000001";
try
{
mydb.Order.Add(order);
mydb.SaveChange();
}
catch (Exception exception)
{
if(excpetion == duplicate key) // pseudo code, don't know the error for duplicate keys
{
order.OrderID = m0000002;
}
}

Is there a simpler way to transfer data between an android application and a server database?

At the moment, in my app, I currently have an SQLite database, for where I store relevant information that needs to be eventually sent to the database or for later recalling in the app (or both). This is done the traditional way using the SQLiteOpenHelper class:
public class SQLiteHelper extends SQLiteOpenHelper {
// define constants to store names of each table and each field name
// Tables
public static final String TABLE_VISIT_DETAILS = "VisitDetails";
...
private static final String DATABASE_NAME = "Projects.db";
private static final int DATABASE_VERSION = 41;
// Database table creation sql statements, SQLite requires tables to be
// created in separate statements
private static final String CREATE_TABLE_VISIT_DETAILS = "create table "
+ TABLE_VISIT_DETAILS + "(" + COLUMN_ID
+ " integer primary key autoincrement, " + COLUMN_PROJECT_NUMBER
+ " text not null, " + COLUMN_SITE_VISIT_ID + " integer, "
+ COLUMN_SCHEDULED_START_TIME + " integer, "
+ COLUMN_SCHEDULED_END_TIME + " integer, " + COLUMN_POSTCODE
+ " text, " + COLUMN_SUBMITTED + " text, " + COLUMN_SITE_NAME
+ " text, " + COLUMN_SITE_ADDRESS + " text, " + COLUMN_PROJECT_TYPE
+ " text, " + COLUMN_CLIENT + " text, "
+ COLUMN_REINSPECTION_PROJECT + " text, " + COLUMN_VISIT_NUMBER
+ " integer);";
...
etc
And I just store objects quite simply. Before, I had used JSONObject and JSONArray to send JSON requests to the server, but now I've changed that to Gson for a lot easier use of serialisation and make the need to use the put method for each attribute into the json objects.
I have an API set up on my server which waits on these json objects which it then parses, eg:
[WebInvoke(UriTemplate = "UploadSurveyData/{token}", Method = "POST", ResponseFormat = WebMessageFormat.Json)]
public List<UploadProjectContainerResult> UploadSurveyData(string token, UploadProjectContainer data)
{
List<UploadProjectContainerResult> results = new List<UploadProjectContainerResult>();
MobileAssessorAuthenticationResults authResult = ValidateToken(new Guid(token));
SqlCommand command = null;
SqlDataReader reader = null;
if (authResult == MobileAssessorAuthenticationResults.Success)
{
results.Add(uploadQuestionnaireResponse(token, data.questionnaireResponses));
results.Add(uploadBuildings(token, data.buildings));
results.Add(uploadFloors(token,data.floors ));
results.Add(uploadLocations(token, data.locations));
String projectDir = "";
command = new SqlCommand("[dbo].[GetProjectDir]", _connector.Connection);
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.AddWithValue("#projectNo", data.siteInfo.projectNo);
reader = command.ExecuteReader();
if (reader.HasRows)
{
reader.Read();
projectDir = reader.GetString(0);
}
results.Add(uploadSiteInfo(token, data.siteInfo, projectDir));
results.Add(uploadSubmission(token,data.submission, projectDir, data.scheduleId));
}
return results;
}
It makes an object of the container and then goes through each thing in the container and runs a stored procedure in a SQL database to add them to the database and returns a result for each one (whether it's successful or not). It then returns an array of those results back, and tells the app each of them indicating to the user if they were successful or not.
It's quite annoying adding new stuff, or even changing stuff using this system as it has to be changed in several places.
I was wondering if there was something I could implement to make this a lot simpler and quicker to do or if any it were redundant and could be be replaced by something else.
On the whole, I'd just like to cut down the whole process a lot for this and future projects. I don't mind starting from scratch again, if only to increase productivity later on.
I'm using C# with .NET framework as my webservice API, SQL Server 10.50.1600 as my SQL database, android with 2.3.3 as my minimum platform for the devices, so these are my limitations and are the things that aren't flexible to change. Any external libraries are welcome, of course, if they are compatible.
If you'd like me to include more of my code, feel free to ask. It will become commercial code for the company I work for, so I cannot disclose the entire source, but I am willing to show as much as is needed (if that makes sense).
Thank you very much for reading and helping me!
*EDIT: * Bump.
Kryonet transfers object graphs and comes with its own serialization library. It's pretty simple and quick to implement as far as client / server networking. Concerning the refactoring of your code, you're probably in the best position to pull out the redundant pieces.

Unique number identifier generation

I have to create logic for generation unique number identifier for records in database. id, generated in database is a separate column.
At this moment, when user calls "create record" action, I save new record, get its database id, generate record number using this id, then put it to the edit form.
Using this way means that all entity fields should be nullable to save record to database.
I don't like this way. I know that should be better way.
Is there a better practice to generate unique number identifier? What is possibility of generating non-unique random numbers?
Thank you
The pattern that you're using, of saving an empty record simply to get the ID, is not a good one.
The standard approach, and the one that I'd recommend, is for Create Record to simply display an empty form (the ID at this point will typically be 0). The user fills in the form and the data is only committed to the database when the user clicks Save. The ID should be an IDENTITY column.
A problem with your approach is that if users do not complete the form, you end up with lots of incomplete records in your database. And, of course, it makes it much more difficult to handle data validation and integrity.
An alternative approach, if you really must display the ID to the user, is to have a separate table containing a row with a "Next Record ID" column. This column can be incremented and returned as an atomic operation and used to populate the ID of your new record. You still don't create the real record, just increment this "Next Record ID" in your Create Record action. Using this approach, you can use the same approach for multiple entities by having separate rows for each in this "Record IDs" table. Bear in mind that if the user does not ultimately save the record to the database, an ID will still have been 'used up'. The numbers will still be unique and will be chronological but won't necessarily be contiguous.
I don't get it, but, if you are using the uniqueidentifier data type in your database, that translates to Guid in C#, so you can do:
public Guid CreateRecord(MyObject model) {
Guid newId = Guid.NewGuid();
MyTable tbl = new MyTable();
tbl.guid = newId;
// ... other columns
db.MyTable.AddObject(tbl);
db.SaveChanges();
return newId;
}
though what I normally do, is having the PrimaryKey as int and add a uniqueidentifier field named guid (that I use it publically instead the column_id) and remember to index that column.
Code for Table..
CREATE TABLE TblTransactions(
TId varchar(8),
TName varchar(50)
)
C# Code Behind…
protected void Page_Load(object sender, EventArgs e)
{
string id = GenerateId("TblTransactions", "TId", 8, "TRN");
// insert the id along with data in the table
Response.Write(id);
}
public string GenerateId(string TableName, string ColumnName, int ColumnLength, string Prefix)
{
SqlConnection con = new SqlConnection("server=.;integrated security=true;database=EBissCard");
string Query, Id;
int PrefixLength, PadLength;
PrefixLength = Convert.ToInt32(Prefix.Length);
PadLength = ColumnLength - PrefixLength;
Query = "SELECT '" + Prefix + "' + REPLACE(STR(MAX(CAST(SUBSTRING(" + ColumnName + "," + Convert.ToString(PrefixLength + 1) + "," + PadLength + ") AS INTEGER))+1," + PadLength + "),' ',0) FROM " + TableName;
SqlCommand com = new SqlCommand(Query, con);
con.Open();
if (com.ExecuteScalar().ToString() == "")
{
Id = Prefix;
for (int i = 1; i <= PadLength - 1; i++)
{
Id += "0";
}
Id += "1";
}
else
{
Id = Convert.ToString(com.ExecuteScalar());
}
con.Close();
return Id;
}
An idea to generate a unique number for a record is to use the time() in milliseconds (since a reference point of time, say, 01/01/2010).
However, if there are 2 records that are simultaneously getting updated, this may cause an issue. To solve this problem, if each of the user can be assigned a number (when creating the userID), a combination (concatenation) of that "user number" and time in milliseconds will give you the unique number you need.
Try the Random class from .net itself.

Categories

Resources