Import text file collection into SQL Server table - c#

I am trying to collect data from a text file in order to populate a table in Sql Server. The collection part is working but at "ExecuteNonQuery" I get the "No mapping exists from object type System.Collections.Generic.List" error. I've researched this error here and at other sites and from what I can gather, the error is caused by trying to populate a table with an array or there is something wrong with my parameters. I've tried various adjustments to the code which populates the table. Haven't touch the collection code as I hate to fix what isn't broken. Here is my code:
var mbrNbr = new List<string>();
var sPages = new List<int>();
var ePages = new List<int>();
var startPage = 0;
var endPage = 0;
using (var sr = new StreamReader(#"\\path\textFile.txt"))
{
while (sr.Peek() > 0)
{
var line = sr.ReadLine();
var memberNumber = line.Substring(698,11);
var passThru = line.Substring(698,11);
var oceMax = Convert.ToInt32(line.Substring(910, 3));
if (passThru.Equals(memberNumber))
{
mbrNbr.Add(memberNumber);
startPage = endPage + 1;
endPage += oceMax * 2;
ePages.Add(endPage);
sPages.Add(startPage);
}
}
}
var sqlConn = new SqlConnection("server/db conneciton");
sqlConn.Open();
var updateSql = #"update myTable
set MemberNbr = #memberNumber,
StartPage = #startPage, EndPage = #endPage";
using (SqlCommand cmd = new SqlCommand(updateSql, sqlConn))
{
cmd.CommandTimeout = 6000;
cmd.Parameters.AddWithValue("#memberNumber", mbrNbr);
cmd.Parameters.AddWithValue("#startPage", sPages);
cmd.Parameters.AddWithValue("#endPage", ePages);
cmd.ExecuteNonQuery();
}
sqlConn.Close();
In an effort to construct a specific question, here goes: Does SQL Server not accept an array or is it a parameter issue or both?

Related

How to return a data from while c# using oracle 11g

I need to return all values from my table. How to write a code inside while?
var stringConnection = "Data Source = X; User Id = X; Password = X";
var sql = "SELECT * FROM TABLE";
OracleConnection _oracleConnection = new OracleConnection(stringConnection);
_oracleConnection.Open();
OracleCommand cmd = new OracleCommand(sql, _oracleConnection);
var dr = cmd.ExecuteReader();
var list = new List<dynamic>();
while(dr.Read())
{
// my doubt is here
}
return list;
var stringConnection = "Data Source = X; User Id = X; Password = X";
var sql = "SELECT * FROM TABLE";
OracleConnection _oracleConnection = new OracleConnection(stringConnection);
_oracleConnection.Open();
OracleCommand cmd = new OracleCommand(sql, _oracleConnection);
var dr = cmd.ExecuteReader();
var list = new List<dynamic>();
while(dr.Read())
{
// **** read column name data from table ****
string Id = (string)dr["Id"];
string company = (string)dr["company"];
string city = (string)dr["City"];
var objItem = new { Id = Id, company = company, city = "city" };
list.Add(objItem);
}
return list;
You have several options. 1 - load DataSet from OracleDataReader. There you will have all your data.
2 - you can still use select *... but you need a model. Then create List<SomeModel> instead of List<dynamic> with
while (reader.Read())
{
model.Property = reader["columnName"]; // will need convert type and take care of DB null. Can use existing extnsions
. . . .
}
3 - For arbitrary number of columns use OracleDataReader.FieldCount and some storage like List<object[]>
var data = new List<object[]>();
var fCnt = reader.FieldCount;
while (reader.Read())
{
var arr = new Object[fCnt];
for(int i = 0; i < fCnt; i++)
arr[i] = reader[i];
data.Add(arr);
}
The unfortunate part with #3 is that in the end you can get jagged array and not 2-dimentional one but you now have enough info to convert it. But I don't remember when I needed to do #3. So think about #1 and #2
And one more thing - absolutely no need for dynamic here. Stay away.

Update table row in database c# console app

trying to update a column of null values with instagramIds, this is my current approach but the console app just keeps running and doesn't update any values in the database.
public static async Task<InstagramUser> ScrapeInstagram(string url)
{
using (var client = new HttpClient())
{
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
// create html document
var htmlBody = await response.Content.ReadAsStringAsync();
var htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(htmlBody);
// select script tags
var scripts = htmlDocument.DocumentNode.SelectNodes("/html/body/script");
// preprocess result
var uselessString = "window._sharedData = ";
var scriptInnerText = scripts[0].InnerText
.Substring(uselessString.Length)
.Replace(";", "");
// serialize objects and fetch the user data
dynamic jsonStuff = JObject.Parse(scriptInnerText);
dynamic userProfile = jsonStuff["entry_data"]["ProfilePage"][0]["graphql"]["user"];
List<String> columnData = new List<String>();
//Update database query
string connectionString = #"Server=myProject-dev-db.cothtpanmcn7.ap-southeast-2.rds.amazonaws.com;Database=Projectdb;User Id=testadmin;Password=U8gs7vb7C7yvakXf;MultipleActiveResultSets=true;Trusted_Connection=False;";
using (SqlConnection con = new SqlConnection(connectionString))
{
//get null values from database
string query = "Select * from ApplicationUser where InstagramId is null";
using (SqlCommand command = new SqlCommand(query, con))
{
command.Connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
columnData.Add(reader.GetString(0));
}
}
}
for (int index = 0; index < columnData.Count(); index++)
{
//get username and scrape info
var instagramInfo = new InstagramUser
{
Id = userProfile.id,
};
columnData.Add(instagramInfo.ToString());
}
SqlCommand cmd = new SqlCommand("Update ApplicationUser Set InstagramId = '" + columnData + "'" + "where InstagramUsername = '" + userprofile.username + "'", con);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
// create an InstagramUser
var instagramUser = new InstagramUser
{
FullName = userProfile.full_name,
FollowerCount = userProfile.edge_followed_by.count,
FollowingCount = userProfile.edge_follow.count,
Id = userProfile.id,
url = url
};
return instagramUser;
}
else
{
throw new Exception($"Something wrong happened {response.StatusCode} - {response.ReasonPhrase} - {response.RequestMessage}");
}
}
}
The current output:
{"FullName":null,"FollowerCount":0,"FollowingCount":0,"Id":"6978701146","url":null}
{"FullName":null,"FollowerCount":0,"FollowingCount":0,"Id":"6978701146","url":null}
{"FullName":null,"FollowerCount":0,"FollowingCount":0,"Id":"6978701146","url":null}
{"FullName":null,"FollowerCount":0,"FollowingCount":0,"Id":"6978701146","url":null}
{"FullName":null,"FollowerCount":0,"FollowingCount":0,"Id":"6978701146","url":null}
My current approach is to create a list, add all instagramIDs which are null to that list. From there I add all instagramIds to that list after scraping Instagram for their usernames e.g. https://www.instagram.com/therock/?__a=1
then I update the column InstagramUsername with their instagram Ids

using Oracle Exadata and C#: Paging data from Oracle to retrieve in datatable

I am using Oracle Exadata as database and using that in a ASP.NET C# Web application.
I am trying to query the data from the database and fetch the data in data table. The data is too huge as I am using a select * option. The data table errors out with memory issues and would not be the right approach as well.
I am trying to check if a paging model can be applied.
I have used the below code model with MS SQL, which works. I am not sure how this can be applied in Oracle query. Below is the code for MS SQL.
public List<DataTable> GetDataSet()
{
var dataTables = new List<DataTable>();
var totalRecords = 0;
var tableIndex = 1;
using (var cn = new SqlConnection {ConnectionString = ConnectionString})
{
using (var cmd = new SqlCommand {Connection = cn})
{
var selectStatement =
#"SELECT Cust.CustomerIdentifier,
Cust.CompanyName,
Cust.ContactName,
C.[Name] AS Country
FROM dbo.Customers AS Cust
INNER JOIN dbo.Countries AS C
ON Cust.CountryIdentifier = C.CountryIdentifier
ORDER BY Cust.CustomerIdentifier
OFFSET #Offset ROWS
FETCH NEXT 25 ROWS ONLY;";
var countStatement = "SELECT COUNT(Cust.CustomerIdentifier) FROM dbo.Customers AS Cust";
cmd.CommandText = countStatement;
cn.Open();
totalRecords = Convert.ToInt32(cmd.ExecuteScalar());
cmd.CommandText = selectStatement;
cmd.Parameters.Add("#OffSet", SqlDbType.Int);
for (var index = 0; index < totalRecords; index++)
{
if (index % 25 == 0)
{
cmd.Parameters["#OffSet"].Value = index;
var dt = new DataTable() {TableName = $"Table{tableIndex}"};
dt.Load(cmd.ExecuteReader());
dataTables.Add(dt);
tableIndex += 1;
}
}
}
}
return dataTables;
}
I am trying to achieve the same functionality with Oracle. How to query the Oracle to get the data in this same way. Thanks

SQL query on ADO.net limitation with 2100+ parameters

I am trying to implement an ADO.NET code which executes the SQL query with multiple parameters. Looks like SQL parameter limit is 2100 and does not accept more than this limit. How do I achieve with my below code to have this accept more than the limitation.
I am finding it difficult to understand the implementations when validating online articles related how to send the queries in subsets or chunks to fulfill my request.
This is my code:
using (Connection = new SqlConnection(CS))
{
Connection.Open();
string query = "SELECT FamilyID, FullName, Alias FROM TABLE (nolock) WHERE FamilyID IN ({0})";
var stringBuiler = new StringBuilder();
var familyIds = new List<string>();
string line;
while ((line = TextFileReader.ReadLine()) != null)
{
line = line.Trim();
if (!familyIds.Contains(line) & !string.IsNullOrEmpty(line))
{
familyIds.Add(line);
}
}
var sqlCommand = new SqlCommand
{
Connection = Connection,
CommandType = CommandType.Text
};
var index = 0; // Reset the index
var idParameterList = new List<string>();
foreach (var familyId in familyIds)
{
var paramName = "#familyId" + index;
sqlCommand.Parameters.AddWithValue(paramName, familyId);
idParameterList.Add(paramName);
index++;
}
sqlCommand.CommandText = String.Format(query, string.Join(",", idParameterList));
var dt = new DataTable();
using (SqlDataReader sqlReader = sqlCommand.ExecuteReader())
{
dt.Load(sqlReader);
}
try
{
if (dt.Rows.Count > 0)
{
OutputdataGridView.DataSource = lstDownloadOwnerOutput;
OutputdataGridView.ColumnHeadersDefaultCellStyle.Font = new Font(DataGridView.DefaultFont, FontStyle.Bold);
OutputdataGridView.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
Gridviewdisplaylabel.Text = "Total no of rows: " + this.OutputdataGridView.Rows.Count.ToString();
}
else if (dt.Rows.Count == 0)
{
MessageBox.Show("Data returned blank!!!");
}
}
catch (Exception Ex)
{
if (Connection != null)
{
Connection.Close();
}
MessageBox.Show(Ex.Message);
}
}
Having a WHERE IN clause with 2100, or even 100, parameters is generally not good coding practice. You might want to consider putting those values into a separate bona fide table, e.g.
families (ID int PK, ...)
Then, you may rewrite your query as:
SELECT FamilyID, FullName, Alias
FROM TABLE (nolock)
WHERE FamilyID IN (SELECT ID FROM families);
You could also express the above using an EXISTS clause or a join, but all three approaches might just optimize to a very similar query plan anyway.
You can just add a table load call every 2000 parameters in your code:
var index = 0; // Reset the index
var idParameterList = new List<string>();
var dt = new DataTable();
foreach (var familyId in familyIds) {
var paramName = "#familyId" + index;
sqlCommand.Parameters.AddWithValue(paramName, familyId);
idParameterList.Add(paramName);
index++;
if (index > 2000) {
sqlCommand.CommandText = String.Format(query, string.Join(",", idParameterList));
using (SqlDataReader sqlReader = sqlCommand.ExecuteReader())
dt.Load(sqlReader);
sqlCommand.Parameters.Clear();
idParameterList.Clear();
index = 0;
}
}
if (index > 0) {
sqlCommand.CommandText = String.Format(query, string.Join(",", idParameterList));
using (SqlDataReader sqlReader = sqlCommand.ExecuteReader())
dt.Load(sqlReader);
}
For dynamic sql like this, I generally recommend using a Table-Valued Parameter.
It does require a bit of setup: you have to create a user-defined Type in the DB to hold the values, but that is a fairly trivial operation:
CREATE TYPE PrimaryKeyType AS TABLE ( VALUE INT NOT NULL );
We generally use these in conjunction with stored procedures:
CREATE PROCEDURE dbo.getFamily(#PrimaryKeys PrimaryKeyType READONLY)
AS
SELECT FamilyID, FullName, Alias
FROM TABLE (nolock) INNER JOIN #PrimaryKeys ON TABLE.FamilyID = #PrimaryKeys.Value
GO
However, you can also use inline SQL if you prefer.
Assigning the values to the stored proc or inline parameter is fairly straightforward, but there is one gotcha (more later):
public static void AssignValuesToPKTableTypeParameter(DbParameter parameter, ICollection<int> primaryKeys)
{
// Exceptions are handled by the caller
var sqlParameter = parameter as SqlParameter;
if (sqlParameter != null && sqlParameter.SqlDbType == SqlDbType.Structured)
{
// The type name may look like DatabaseName.dbo.PrimaryKeyType,
// so remove the database name if it is present
var parts = sqlParameter.TypeName.Split('.');
if (parts.Length == 3)
{
sqlParameter.TypeName = parts[1] + "." + parts[2];
}
}
if (primaryKeys == null)
{
primaryKeys = new List<int>();
}
var table = new DataTable();
table.Columns.Add("Value", typeof(int));
foreach (var wPrimaryKey in primaryKeys)
{
table.Rows.Add(wPrimaryKey);
}
parameter.Value = table;
}
The thing to watch out for here is the naming of the parameter. See the code in the method above that removes the database name to resolve this issue.
If you have dynamic SQL, you can generate a correct parameter using the following method:
public static SqlParameter CreateTableValuedParameter(string typeName, string parameterName)
{
// Exceptions are handled by the caller
var oParameter = new SqlParameter();
oParameter.ParameterName = parameterName;
oParameter.SqlDbType = SqlDbType.Structured;
oParameter.TypeName = typeName;
return oParameter;
}
Where typeName is the name of your type in the DB.

SQL Sever read data to array in C#

Hi i am trying to create a auto fill in my application.
but some how its not filling the array. can someone help me?
i am new to C# so i am sorry for stupid mistakes.
private void autonrTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
try
{
int i = 0;
var check[i];
using (var con2 = new SqlConnection(#"Data Source=DESKTOP-RSEBNR7;Initial Catalog=AudiDealer;Integrated Security=True"))
using (var cmd2 = new SqlCommand("SELECT * FROM auto where autonr = " + autonrTextBox.Text, con2))
{
con2.Open();
check = cmd2.ExecuteScalar();
con2.Close();
autonrTextBox.Text = check[0];
kentekenTextBox.Text = check[1];
merkTextBox.Text = check[2];
modelTextBox.Text = check[3];
kleurTextBox.Text = check[4];
categorieTextBox.Text = check[5];
pkSTextBox.Text = check[6];
apkTextBox.Text = check[7];
kilometerstandTextBox.Text = check[8];
bijtellingTextBox.Text = check[9];
energielabelTextBox.Text = check[10];
}
}
catch
{
MessageBox.Show("Dit Auto nummer komt niet voor in de database. controleer deze en probeer opnieuw","Error");
}
}
You have to use ExecuteReader() even if you want to read a single record (ExecuteScalar returns the single value):
// I've hidden the connection string by ...
using (var con2 = new SqlConnection(#"...")) {
// using will close connection for you, do not call Close() direct
con2.Open();
// Let sql be readable and parametrized
string sql =
#"SELECT *
FROM auto
WHERE autonr = #prm_autonr";
using (var cmd2 = new SqlCommand(sql, con2)) {
cmd2.Parameters.AddWithValue("#prm_autonr", autonrTextBox.Text);
using (var reader = cmd2.ExecureReader()) {
// Do we have any records?
if (reader.Read()) {
// To be on the safe side use Convert.ToString():
// what if the database field is of type Number(8, 5)? NVarChar2(11)?
autonrTextBox.Text = Convert.ToString(reader[0]);
kentekenTextBox.Text = Convert.ToString(reader[1]);
merkTextBox.Text = Convert.ToString(reader[2]);
modelTextBox.Text = Convert.ToString(reader[3]);
kleurTextBox.Text = Convert.ToString(reader[4]);
categorieTextBox.Text = Convert.ToString(reader[5]);
pkSTextBox.Text = Convert.ToString(reader[6]);
apkTextBox.Text = Convert.ToString(reader[7]);
kilometerstandTextBox.Text = Convert.ToString(reader[8]);
bijtellingTextBox.Text = Convert.ToString(reader[9]);
energielabelTextBox.Text = Convert.ToString(reader[10]);
}
}
}
}
You must use ExecuteReader. The ExecuteScalar return only single data. ex: count, sum, min, max. aggregate functions
https://msdn.microsoft.com/en-us/library/9kcbe65k(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar(v=vs.110).aspx

Categories