Dot Net Fluke: Getting by on C# for iSeries RPG Developers

Useful tutorials on C# and .NET for RPG iSeries AS/400 developers. Brought to you from the folks at AranRock Consulting

8/7/08

How to video: Access data on iSeries using ADO.NET

Here is a super simplified video example of a C# application reading from a table on an iSeries. It uses the IBM .net managed provider (See Different ways to access iSeries data and this) . You have this  if you have IBM Client Access. If not, download the technology preview here. Sound problem? jiggle the player control if the sound goes out (I'm trying out demo utility software let me know what one you use.)
.

To view the video click here.

To download the project used in the video, click here.

Subscribe to DotNetFluke to receive weekly useful tips for integrating .NET with the iSeries.
If you have any iSeries/.NET integrations questions or suggestions for articles email me at cbyrne+blog@AranRock.com

Labels: , , , , ,

3/18/08

C# Subfile - iSeries data in a C# Grid -2 no coding (with Video)

Well almost no coding.

If you look at my previous post where I showed how to code a grid in C# using data from the iSeries we manually coded the grid, the data set and the connection. This example accomplishes the same result except you'll be done in under 5 minutes!  It uses the IDE to build the grid, data set, adapter, connection and SQL command.

The video also shows how to add in the iSeries .net data components to your Visual Studio toolbox.
This post easier shown than discussed - so check out the following video.
play

Steps

  1. Create a windows form application project
  2. Add in the IBM dll to your references
  3. Add in the IBM data tools to your toolbox using Tools, Choose Toolbox items and filter 'idb2'
  4. Add a basic grid to your form
  5. Drag the iDB2Connection, IDB2Command, iDB2DataAdapter and a data set to your form
  6. Configure each by right clicking and selecting properties
  7. Double click outside the grid to bring up the code for the Load method of the form.
  8. Add in the following code
    iDB2DataAdapter1.Fill(dataSet1);
    dataGrid1.DataMember = dataSet1.Tables[0].TableName;
  9. Run the program!

Labels: , , , , , ,

3/17/08

C# Subfile - Display an iSeries table in a Grid

We're all used to subfiles on the iSeries. Who can fondly recall many a debate over page by page vs. load all subfile?   How do you create the equivalent of a subfile in .Net?

Easy.

images

Download the visual studio project from here.

subfile

Here's a basic example to get started. The Visual Studio IDE can actually do a lot of the work for you. You can even create a grid (read subfile) with just one or two lines of code. (Post to come)  However, it's more prudent to begin with code you can understand rather than wading through what looks like binary spaghetti.

This example also introduces data sets and data tables. Data sets are just like data structures but without any definition and data tables are just like the field definitions of data structures -not to be confused with tables in databases. We use Data sets and data tables to disconnect from the data source. Connect to the data source, get the data, fill the data set with the data, disconnect from the data source and use the data set in lieu of the actual data. Another way to think of data sets is to think of them as a cache, bucket, container, plastic bag. See my earlier post on data sets for more info.

 

Steps

  1. Define your grid (i.e. subfile)
  2. Attach the grid to your form (VS creates one for you auto-)
  3. Create a data set to hold your data
  4. Create a data table to define the fields in the data set
  5. Add the data table to the data set
  6. Connect  to your iSeries
  7. Execute an SQL statement to read from a table
  8. Read each row and add to the data set
  9. Disconnect from the iSeries
  10. Attach the data set to the grid
  11. Display the grid

It sounds like a lot of work just to output data to a grid - and it is. Why bother with the data set and the table - can't I just write directly out the grid? Yes you can - but this example is here to show you not only how to display data in a grid from the iSeries but how to best manage that data as well. A Data Set will help you do that. 
It is true that there are much simpler approaches on the iSeries but that comes at a price. Once you get out of the db2 and green screen box things get quite tricky on the As/400.  .Net is more complicated yes but its complexity comes from flexibility.

iSeries prerequisites:

The table on the iSeries in this example is called customers. Create it in library QGPL
create the table in DDS or go into SQL by typing 'strsql' in the iSeries command prompt and create the table as follows:

CREATE TABLE QGPL/CUSTOMERS (NAME CHAR (30 ) NOT NULL WITH DEFAULT,
BALANCE DEC (5 ) NOT NULL WITH DEFAULT)

Add records using the INSERT sql command, DBU or your favorite data editor on the iSeries

C# Code:

This is the code for the form. The 'Program.cs' in solution explorer is unchanged. Simply create a windows project, double click on the form that appears and replace all the code with the code below. Insert your iSeries IP address and make sure you have created the iSeries table as describe above or replace with your own ensuring that you correctly specify the columns.  

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using IBM.Data.DB2.iSeries; // Make sure you add this under 'References' in Solution Explorer
// You need the above reference as a dll which is part of iSeries client access.

namespace iSeries_Grid
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //Define the grid size
            DataGrid subfile = new DataGrid();
            subfile.Location = new Point(0, 0);
            subfile.Size = new Size(400, 500);

            //Attach it to the form
            Controls.AddRange(new Control[] { subfile });


            // Create a DataSet to hold data from iSeries Table
            DataSet dataStructure = new DataSet();

            //Create a table to hold the iSeries data
            DataTable dt = new DataTable("Customers");
            dt.Columns.Add("Name");
            dt.Columns.Add("Balance");


            //Add the datatable to the data set
            dataStructure.Tables.Add(dt);

            // Open connection to the iSeries
            iDB2Connection conn = new iDB2Connection();
           conn.ConnectionString = "DataSource=192.168.0.1";

 // You can put "UserID=myuserid;Password=mypass" 
//
if you don't want to be prompted

// Create a command to select records from the customer table
iDB2Command command = new iDB2Command();
command.CommandText = "Select * from qgpl.customers";
command.Connection = conn;
// ties the command to the connection to the iSeries

conn.Open();

// Execute the sql statement. Get a Data Reader object
iDB2DataReader readFile = command.ExecuteReader();

// Read each row from the table and output the results into the data set

while (readFile.Read())
{
// Create a row to hold data
DataRow datarow = dataStructure.Tables["customers"].NewRow();

datarow["Name"] = readFile.GetString(0);
datarow["Balance"] = readFile.GetiDB2Integer(1);

// add the row to the data table customer
dataStructure.Tables["customers"].Rows.Add(datarow);


}

// Clean up - Close connections
readFile.Close();
command.Dispose();
conn.Close();

// Attach the data set to the data grid
subfile.DataSource = dataStructure;
subfile.DataMember = dataStructure.Tables[0].TableName;



// Display the subfile
subfile.Show();


} // End of Method


} //End of Class

} // End of Namespace



 



This code is based on an example in the IBM .Net Redbook modified

for this post.

Labels: , , , , ,

1/17/08

Datasets are what?

Datasets are a layer between the actual database and your application. When you need to connect to different tables and databases, datasets can help by separating all the connecting to your different data stores and working on the actual data. The analogy with RPG is that datasets are data structures. If you read a table in an RPG program and the put that data into a data structure, updated the fields in that data structure then moved the data structure back to your table then the dataset is the data structure and the bit that moves data between the table is the data adapter.
You don't need all this of course. It's part of .NET, specifically ADO.NET - that part of the framework that's supposed to make it easier to build complex data access application. The stuff that manages and brings it in and out of your application . Kind of like the way the RPG cycle (remember that?) reads in a table automatically. You can just read and write from any database without using datasets and adapters. It's just much easier and less error prone when you use data sets and adapters to manage your data. The IDE automatically creates these when you drop a table onto a form.

When you look at the code to fill a dataset from an adapter you can see there's not much too it. The key term here is Dataset. Datasets are completely separated from the database. Think of them as a data structure where you load data from your table to. The data structure knows nothing of the table where it got the data. It's just used to hold the data in memory. All queries, updates etc. are done to the Dataset not to the data store. We let the dataadapter take care of fetching data to and from the actual table.


// build a command object and prepare an SQL statement so that you can look at your table
SqlCommand buildData = conn.CreateCommand();

cmd.CommandText = "Select * from Orders where OrdQty >100";
// Build the Data Adapater - this fills a data set
SqlDataAdapter dataAdapter = new SqlDataAdapter(buildData);

// Now create the data set. The data structure which contains the data retrieved by the data adapter
DataSet orderDataSet = new DataSet();

// Populate the dataset with the Data Adapter
dataAdapter.Fill(dataSet);

Labels: , , , , ,

11/15/07

Calling a program on an iSeries with .net

Here's an easy way to call a program on the AS/400 with .net. What's neat about this function is that it also accepts a return argument.

Requirements:
  1. Client Access
    This method uses the Client Access library so you will need to have Client Access installed on your PC. Specifically you need cwbx.dll which is in the Iseries access folder C:\Program Files\IBM\Client Access\Shared
    Add this into your Visual Studio project as a reference
  2. The host server on the iSeries must be started using STRHOSTSVR SERVER(*ALL)
    Copy the code below into Visual Studio



    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using cwbx; // cwbx.dll is in the Iseries access folder C:\Program Files\IBM\Client Access\Shared
    // YOu must add it in to you project; Click on your references folder in solution explorer to add it in.

    namespace CallAS400pgm
    {
    class Program
    {


    static void Main(string[] args)
    {

    // Modify the following for your own iSeries

    string AS400Name = "192.168.0.1"; // Change this to the IP address of your machine
    string AS400User = "USER"; // User name to sign on to AS/400
    string AS400Password = "password"; // Password used to sign on to the AS/400
    string AS400Pgm = "DOTNET1"; //Name of program you wish to call on the AS/400
    string AS400Lib = "QGPL"; // Name of library where the program is located


    Console.WriteLine("Creating AS/400 object....");

    cwbx.AS400System AS400 = new cwbx.AS400SystemClass(); // creates an as/400 object
    cwbx.Program program = new cwbx.Program(); // Create a program object

    AS400.Define(AS400Name); // IP of AS/400

    program.system = AS400;
    program.system.UserID = AS400User; // Your user name
    program.system.Password = AS400Password; // Your password

    // define the name of the program you want to call on the iSeries
    program.LibraryName = AS400Lib; //Library where your program is located
    program.ProgramName = AS400Pgm; // Program that this app will call

    // NOTE: before you sign on, the host server on the iSeries must be started using STRHOSTSVR SERVER(*ALL)
    Console.WriteLine("Signing on to " + AS400Name);
    AS400.Signon();
    AS400.Connect(cwbcoServiceEnum.cwbcoServiceRemoteCmd);

    if (AS400.IsConnected(cwbcoServiceEnum.cwbcoServiceAll) == 0)
    {
    Console.WriteLine("Not connected");
    }
    else
    {
    ProgramParameters parms = new ProgramParameters(); // must create parameter collection
    // parms.Clear(); // if you have no parm use this statement

    // Define the parms you are sending and receiving from the iSeries pgm
    parms.Append("MsgToAS400", cwbrcParameterTypeEnum.cwbrcInput, 30); // // Input parm called 'MsgToAS400;
    parms.Append("ReplyFromAS400", cwbrcParameterTypeEnum.cwbrcOutput, 30); // create a parameter object name, type & length

    // puts a value into the parameter object
    StringConverter strcon = new StringConverterClass();
    strcon.Length = 30;
    parms["MsgToAS400"].Value = strcon.ToBytes(" This is from a dot net pgm, hi");


    try
    {
    Console.WriteLine("Sending a message to the iSeries....");

    Console.WriteLine("Calling program on the AS400....");
    program.Call(parms); // Runs until job is completed

    // Get the return value from the ISeries pgm

    String reply = strcon.FromBytes(parms["ReplyFromAS400"].Value);
    Console.WriteLine(reply);
    //This program dotnet1 is called on the iSeries. dotnet1 has 2 parameters
    // it takes the first and displays it to a user
    // it then sends back a message to this class in ReplyFromAS400

    Console.ReadLine();


    }
    catch (Exception e)
    {
    foreach (Error error in AS400.Errors)
    {
    Console.WriteLine(error.ToString());
    }

    throw;
    }

    }


    }
    }
    }


Labels: , , , , , , , ,