C# & Oracle Query Database with resepct to an organization - c#

I am writing a C# application to pull specific items from an Oracle database. These items are specific to an organization inside of the Oracle E-Business Suite R12. The goal is to be able to query this but I have zero idea how!
The image below shows how the folder structure is laid out. As you can see targetted table is in
Data Table 2 - > Folder C - > Table Found
Once Targetted Table is Selected, a new dialog opens, for choosing an organization. For this example we will take Org 2
The C# Code I have written:
OracleConnection con = new OracleConnection();
// Oracle for items: Data Table 2 - > Folder C -> Targetted Table -> Item -> Find
con.ConnectionString = "Data Source=(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = host.company.com)" +
"(PORT = 1521))(CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = Data Table 2))); " +
"Password= WhiteRabbit1! ;User ID=Mr_Anderson";
con.Open();
Console.WriteLine("Connected to Oracle" + con.ServerVersion);
OracleCommand cmd = new OracleCommand();
cmd.Connection = con;
cmd.CommandText = "SELECT [Level], [Item], [Description] FROM [Targetted Table]";
cmd.CommandType = CommandType.Text;
OracleDataReader dr = cmd.ExecuteReader();
while (dr.Read())
// Add data
Which outputs the error:
Oracle.DataAccess.Client.OracleException: 'ORA-12541: TNS:no listener'
At the Line: con.Open();
EDIT: Changed HOST = host.company.com to HOST = host.company.com\ and we get a new error output!
Oracle.DataAccess.Client.OracleException: 'ORA-12545: Connect failed because target host or object does not exist'
I am trying to follow this guide: https://o7planning.org/en/10509/connecting-to-oracle-database-using-csharp-without-oracle-client#a1814792
But not sure what step messed up the code. My guess is the port, but I don't know where to look for that. Saw an article that said use 1521 for database access

Related

OleDbCommand with ORACLE query not updating table

I have tried everything, googled for days, but nothing I found helped me.
I have Oracle 9i db, table TIME_UNITS that have several fields - for my purposes I use only 3, defined as:
CODE - VARCHAR2(6), FOR_IN - VARCHAR2(1), FOR_OUT - VARCHAR2(1). My code is:
string strConString = "provider=MSDAORA;DSN=myDSN;user id=myUser;password=myPassword";
string strQuery = "UPDATE TIME_UNITS SET FOR_IN='Y', FOR_OUT='Y' WHERE CODE='202003'";
using (OleDbConnection oleDbConn = new OleDbConnection(strConString ))
using (OleDbCommand cmd = new OleDbCommand(strQuery, oleDbConn))
{
oleDbConn.Open();
cmd.Transaction = oleDbConn.BeginTransaction();
int rows = cmd.ExecuteNonQuery();
cmd.Transaction.Commit();
oleDbConn.Close();
}
ExecuteNonQuery returns one row, but when I look into db using sqldeveloper nothing is changed. The same statement works perfectly in sqldeveloper using the same credentials. I've tried with and without transaction begin-commit, but still no change in database. What am I doing wrong?

Oracle Managed Data Reader Returning DBNull for One Database Table

Issue:
I am using the Oracle managed data access client to connect to an Oracle eBS database. When selecting a value from one table I get a result; when changing the table I get a null value.
Background:
In my SQLDeveloper client I can connect to the database and run the following queries:
SELECT MSIB.SEGMENT1
FROM APPS.MTL_SYSTEM_ITEMS_B MSIB
WHERE MSIB.ORGANIZATION_ID = 255 AND MSIB.SEGMENT1 = '03F.211';
-- 1 ROW RETURNED - VALUE OF 03F.211
SELECT MC.SEGMENT1
FROM APPS.MTL_CATEGORIES_VL MC
WHERE MC.SEGMENT1 = 'A0042I';
-- 1 ROW RETURNED - VALUE OF A0042I
Then, in C#, I'm connecting to the database with exactly the same credentials (so it should not be a database permissions issue).
Running this code I get a message box returning what I would expect: 03F.211
OracleConnection oradbcon = new OracleConnection(strOracleConString);
oradbcon.Open();
strQuery = "SELECT MSIB.SEGMENT1 FROM APPS.MTL_SYSTEM_ITEMS_B MSIB WHERE MSIB.ORGANIZATION_ID = 255 AND MSIB.SEGMENT1 = " + ":ITEM_CODE";
// strQuery = "SELECT MC.SEGMENT1 FROM APPS.MTL_CATEGORIES_VL MC WHERE MC.SEGMENT1 = " + ":ITEM_CODE";
OracleCommand oradbcmd = new OracleCommand(strQuery, oradbcon);
oradbcmd.CommandType = CommandType.Text;
OracleParameter p_item_code = new OracleParameter();
p_item_code.OracleDbType = OracleDbType.Varchar2;
p_item_code.Value = "03F.211";
// p_item_code.Value = "A0042I";
oradbcmd.Parameters.Add(p_item_code);
OracleDataReader oradbdr = oradbcmd.ExecuteReader();
oradbdr.Read();
strProductMinor = oradbdr.GetString(0).ToString();
MessageBox.Show(strProductMinor);
But running the code with those commented lines switched I get an error indicating a database null:
OracleConnection oradbcon = new OracleConnection(strOracleConString);
oradbcon.Open();
// strQuery = "SELECT MSIB.SEGMENT1 FROM APPS.MTL_SYSTEM_ITEMS_B MSIB WHERE MSIB.ORGANIZATION_ID = 255 AND MSIB.SEGMENT1 = " + ":ITEM_CODE";
strQuery = "SELECT MC.SEGMENT1 FROM APPS.MTL_CATEGORIES_VL MC WHERE MC.SEGMENT1 = " + ":ITEM_CODE";
OracleCommand oradbcmd = new OracleCommand(strQuery, oradbcon);
oradbcmd.CommandType = CommandType.Text;
OracleParameter p_item_code = new OracleParameter();
p_item_code.OracleDbType = OracleDbType.Varchar2;
// p_item_code.Value = "03F.211";
p_item_code.Value = "A0042I";
oradbcmd.Parameters.Add(p_item_code);
OracleDataReader oradbdr = oradbcmd.ExecuteReader();
oradbdr.Read();
strProductMinor = oradbdr.GetString(0).ToString();
MessageBox.Show(strProductMinor);
What would cause one query to return results but the other to not?
(Finally - forgive my ignorance of C# if anything above is ugly. Years of Oracle experience - first C# program ever... :) )
The issue is language.
APPS.MTL_CATEGORIES_VL is a view that has another view in it's definition:
MTL_CATEGORIES_TL
The views ending in TL are "translated language" meaning they only return results for the language of your database session.
SQL Developer is declaring a default language when I connect.
.NET client is not.
I either need to figure out how to declare a language or re-write my queries to use base tables that don't have language.
Edit: There was a complaint that this wasn't an actual answer, but an explanation.
Here is the actual code that is the answer:
try // Open Connection
{
oradbcon = new OracleConnection(yourConnectionStringHere);
oradbcon.Open();
OracleGlobalization orainfo = oradbcon.GetSessionInfo();
orainfo.Language = "AMERICAN"; // Explicitly Set Language
oradbcon.SetSessionInfo(orainfo);
}

Copying data from one database to another - Out of Memory Exception

I have a task where i want to copy all data from one database to another database & skipping 2 tables. There are more than 200 tables.
I have table structure ready for my 2nd databas.
So as a solution i created a page & on a button click i have below code :-
DataSet ds = new DataSet();
string connectionString = "Data Source=COMP112\\MSSQLSERVER2014;Initial Catalog=HCMBL;Integrated Security=True;Persist Security Info=True";
SqlConnection con = new SqlConnection(connectionString);
//render table name from database
string sqlTable = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' and TABLE_Schema='" + Session["SchemaName"].ToString() + "' and TABLE_NAME!='ENTRY' and TABLE_NAME!='OT' and TABLE_NAME!='BL_ENTRY' and TABLE_NAME!='BL_OT'";
con.Open();
SqlDataAdapter da = new SqlDataAdapter();
SqlCommand cmd = new SqlCommand(sqlTable, con);
cmd.CommandType = CommandType.Text;
da.SelectCommand = cmd;
da.Fill(ds);
con.Close();
//render connection string from WebConfig file
string strcon = ConfigurationManager.ConnectionStrings["SPSchema"].ConnectionString;
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
if (!(ds.Tables[0].Rows[i]["TABLE_NAME"].ToString().Contains("Asp")))
{
string deleteQuery = "Truncate table " + Session["SchemaName"].ToString() + "." + ds.Tables[0].Rows[i]["TABLE_NAME"];
con.Open();
SqlCommand cmdDelete = new SqlCommand(deleteQuery, con);
cmdDelete.ExecuteNonQuery();
con.Close();
DataSet dataSet = new DataSet();
SqlConnection conn = new SqlConnection(strcon);
conn.Open();
string selectData = "select * from " + Session["SchemaName"].ToString() + "." + ds.Tables[0].Rows[i]["TABLE_NAME"];
SqlCommand command = new SqlCommand(selectData, conn);
DataTable dataTable = new DataTable();
SqlDataAdapter dataAdapter = new SqlDataAdapter(selectData, conn);
dataAdapter.FillSchema(dataSet, SchemaType.Mapped);
dataAdapter.Fill(dataSet);
dataTable = dataSet.Tables[0];
conn.Close();
if (dataSet.Tables[0].Rows.Count > 0)
{
//Connect to second Database and Insert row/rows.
SqlConnection conn2 = new SqlConnection(connectionString);
conn2.Open();
SqlBulkCopy bulkCopy = new SqlBulkCopy(conn2);
bulkCopy.DestinationTableName = Session["SchemaName"].ToString() + "." + ds.Tables[0].Rows[i]["TABLE_NAME"].ToString();
bulkCopy.WriteToServer(dataTable);
conn2.Close();
}
}
}
As i run the above code after inserting data in less than 10 tables, it gives out of memory exception & program crashes.
How to handle this? I tried increasing the memory capacity of SQL Server but still same error.
Is there any other way to achieve the task?
What you are doing is very far from the best solution. You are using an ASP.NET MVC process to get all data of your entire database into memory, and then outputting it to another database. If your database is anything more than small and trivial, that will most definitely fill your process's alotted memory.
This type of task should never be done through the memory of a process, but rather using some form of Backup/Restore pattern.
You should look into SSIS projects and create an extract, transfer, and load (ETL) solution, which can be triggered from your ASP.NET MVC solution asynchronously.
An SSIS solution can be triggered from C# code in this way:
var app = new Application();
var package = app.LoadPackage("compiled-package.dtsx", null);
var results = package.Execute();
See this question for a little more information (not specifically about duplicating databases, but has information about triggering SSIS packages from code): How to execute an SSIS package from .NET?
Alternatively
You also have the option of running a query against both databases at once, however this requires some additional plumbing to be done. The user account of your ASP.NET MVC solution needs to have access to both databases. If your databases are hosted on different servers, you also need to link one server to the other: Create linked servers
To perform an insert directly from the output of a select, consider this:
string source = "NAME_OF_SOURCE_DATABASE";
string target = "NAME_OF_TARGET_DATABASE";
string schema = Session["SchemaName"].ToString();
string table = ds.Tables[0].Rows[i]["TABLE_NAME"];
// Uncomment this if you need to deal with autoincrement columns
/*string idInsQuery = $"SET IDENTITY_INSERT {target}.{schema}.{table} ON";
var idInsCommand = new SqlCommand(idInsQuery, conn);
idInsCommand.ExecuteNonQuery();*/
string insQuery = $"INSERT INTO {target}.{schema}.{table} SELECT * FROM {source}.{schema}.{table}";
var insCommand = new SqlCommand(insQuery, conn);
insCommand.ExecuteNonQuery();
// Uncomment this if you need to deal with autoincrement columns
/*string idInsQuery2 = $"SET IDENTITY_INSERT {target}.{schema}.{table} OFF";
var idInsCommand2 = new SqlCommand(idInsQuery2, conn);
idInsCommand2.ExecuteNonQuery();*/
This will only work if the table structures are identical. There might be problems with autoincrement ids or columns with default values, too.
This will copy data from a table in database 1 to a table in database 2
Insert into db2.dbo.table2 (col1,col2)
Select col1,col2 from db1.dbo.table1
Run this sql statement and the data will be copied without a round trip to your app.
Let me know if you find my approach is useful.
First of all, why you want to write down one whole application to do this job while SQL Server have inherited property to do it.
My approach would be configure an Linked Server and configure it which tables you want to copy and which one not.
https://learn.microsoft.com/en-us/sql/relational-databases/linked-servers/create-linked-servers-sql-server-database-engine
Secondly, You can just write down simple stored procedure and schedule that in your sql server to push into another server database as per your schedule. In this way you can control it in N number of ways. I mean about controlling any dependencies(Table level or Business level).
To do this in t-sql, you can use the following system stored procedures to schedule a daily job. This example schedules daily at 1:00 AM. See Microsoft help for details on syntax of the individual stored procedures and valid range of parameters.
DECLARE #job_name NVARCHAR(128), #description NVARCHAR(512), #owner_login_name NVARCHAR(128), #database_name NVARCHAR(128);
SET #job_name = N'Some Title';
SET #description = N'Periodically do something';
SET #owner_login_name = N'login';
SET #database_name = N'Database_Name';
-- Delete job if it already exists:
IF EXISTS(SELECT job_id FROM msdb.dbo.sysjobs WHERE (name = #job_name))
BEGIN
EXEC msdb.dbo.sp_delete_job
#job_name = #job_name;
END
-- Create the job:
EXEC msdb.dbo.sp_add_job
#job_name=#job_name,
#enabled=1,
#notify_level_eventlog=0,
#notify_level_email=2,
#notify_level_netsend=2,
#notify_level_page=2,
#delete_level=0,
#description=#description,
#category_name=N'[Uncategorized (Local)]',
#owner_login_name=#owner_login_name;
-- Add server:
EXEC msdb.dbo.sp_add_jobserver #job_name=#job_name;
-- Add step to execute SQL:
EXEC msdb.dbo.sp_add_jobstep
#job_name=#job_name,
#step_name=N'Execute SQL',
#step_id=1,
#cmdexec_success_code=0,
#on_success_action=1,
#on_fail_action=2,
#retry_attempts=0,
#retry_interval=0,
#os_run_priority=0,
#subsystem=N'TSQL',
#command=N'EXEC my_stored_procedure; -- OR ANY SQL STATEMENT',
#database_name=#database_name,
#flags=0;
-- Update job to set start step:
EXEC msdb.dbo.sp_update_job
#job_name=#job_name,
#enabled=1,
#start_step_id=1,
#notify_level_eventlog=0,
#notify_level_email=2,
#notify_level_netsend=2,
#notify_level_page=2,
#delete_level=0,
#description=#description,
#category_name=N'[Uncategorized (Local)]',
#owner_login_name=#owner_login_name,
#notify_email_operator_name=N'',
#notify_netsend_operator_name=N'',
#notify_page_operator_name=N'';
-- Schedule job:
EXEC msdb.dbo.sp_add_jobschedule
#job_name=#job_name,
#name=N'Daily',
#enabled=1,
#freq_type=4,
#freq_interval=1,
#freq_subday_type=1,
#freq_subday_interval=0,
#freq_relative_interval=0,
#freq_recurrence_factor=1,
#active_start_date=20170101, --YYYYMMDD
#active_end_date=99991231, --YYYYMMDD (this represents no end date)
#active_start_time=010000, --HHMMSS
#active_end_time=235959; --HHMMSS
Let me know in case you need more details on this.
Thanks,
Ayan

Getting Oledb exception when updating column in excel

I am getting the following error "No value given for one or more required parameters." On the ExceuteNonQuery() line of the below code.
System.Data.OleDb.OleDbConnection finalConnection;
System.Data.OleDb.OleDbCommand myCommand = new System.Data.OleDb.OleDbCommand();
string sql = null;
finalConnection = new System.Data.OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source ='c:\\temp\\test.xlsx'; Extended Properties ='Excel 12.0 Xml;HDR=NO';");
finalConnection.Open();
myCommand.Connection = finalConnection;
foreach (VinObject v in VinList)
{
sql = "Update [Sheet1$] set O = ? where S = ?;";
myCommand.Parameters.Add(new OleDbParameter("#amt", v.CostNewAmt));
myCommand.Parameters.Add(new OleDbParameter("#vin", v.VIN));
myCommand.CommandText = sql;
myCommand.ExecuteNonQuery();
}
finalConnection.Close();
I have also tried using a separate command each time, same error.
foreach (VinObject v in VinList)
{
using (OleDbConnection con = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source ='c:\\temp\\test.xlsx'; Extended Properties ='Excel 12.0 Xml;HDR=No';"))
{
con.Open();
string query = #"UPDATE [Sheet1$] SET O = ? WHERE S = ?";
OleDbCommand cmd = new OleDbCommand(query, con);
cmd.Parameters.AddWithValue("#param1", v.CostNewAmt);
cmd.Parameters.AddWithValue("#param2", v.VIN);
cmd.ExecuteNonQuery();
con.Close();
}
}
I am able to modify that into an insert and insert into a new excel spreadsheet, but for the life of me cannot get this update to work. Any idea what I am doing wrong? Thanks for the help.
You're getting the error because Excel doesn't recognize the column letter aliases "O" and "S". It needs the actual column "name", which is the value of the cell in the first populated row. If there is not a valid value in that cell, or you have specified HDR=NO in your connection string, the columns will be named F1, F2...Fn. If you're not sure what the inferred column names are, examine the names using OleDbConnection.GetSchema(String,String[]) or OleDbDataReader.GetName(Int32).
Since you have specified HDR=NO in your connection string, your correct SQL will likely be
"Update [Sheet1$] set F15 = ? where F19 = ?;"
For future reference, check out:
How to query and display excel data by using ASP.NET, ADO.NET, and Visual C# .NET
How to transfer data to an Excel workbook by using Visual C# 2005 or Visual C# .NET
How To Use ADO.NET to Retrieve and Modify Records in an Excel Workbook With Visual Basic .NET. (Still lots of helpful info even if you are using C#)

C# 'select count' sql command incorrectly returns zero rows from sql server

I'm trying to return the rowcount from a SQL Server table. Multiple sources on the 'net show the below as being a workable method, but it continues to return '0 rows'. When I use that query in management studio, it works fine and returns the rowcount correctly. I've tried it just with the simple table name as well as the fully qualified one that management studio tends to like.
using (SqlConnection cn = new SqlConnection())
{
cn.ConnectionString = sqlConnectionString;
cn.Open();
SqlCommand commandRowCount = new SqlCommand("SELECT COUNT(*) FROM [LBSExplorer].[dbo].[myTable]", cn);
countStart = System.Convert.ToInt32(commandRowCount.ExecuteScalar());
Console.WriteLine("Starting row count: " + countStart.ToString());
}
Any suggestions on what could be causing it?
Here's how I'd write it:
using (SqlConnection cn = new SqlConnection(sqlConnectionString))
{
cn.Open();
using (SqlCommand commandRowCount
= new SqlCommand("SELECT COUNT(*) FROM [LBSExplorer].[dbo].[myTable]", cn))
{
commandRowCount.CommandType = CommandType.Text;
var countStart = (Int32)commandRowCount.ExecuteScalar();
Console.WriteLine("Starting row count: " + countStart.ToString());
}
}
Set your CommandType to Text
command.CommandType = CommandType.Text
More Details from Damien_The_Unbeliever comment, regarding whether or not .NET defaults SqlCommandTypes to type Text.
If you pull apart the getter for CommandType on SqlCommand, you'll find that there's weird special casing going on, whereby if the value is currently 0, it lies and says that it's Text/1 instead (similarly, from a component/design perspective, the default value is listed as 1). But the actual internal value is left as 0.
You can use this better query:
SELECT OBJECT_NAME(OBJECT_ID) TableName, st.row_count
FROM sys.dm_db_partition_stats st
WHERE index_id < 2 AND OBJECT_NAME(OBJECT_ID)=N'YOUR_TABLE_NAME'

Categories