before start my question I need to mention I'm c++ programmer not c#, so maybe my code syntax seems wrong. I'm amateur and need improvement!;)
I have a question (maybe it's an idea instead of question) about working with result of data adapter output.
let's take a look at theses lines:
public DataSet CollectData()
{
DataSet result = new DataSet();
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand("dbo.StoredProc1", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
IDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(result);/// filling a dataset
return result;
}
}
as you see this function fill a data set and return it.
Anywhere that I want to use this object I should loop through it like this:
DataSet dataSet = DataObj.CollectData(); /// above function!
string token;
string lemma;
foreach (DataRow row in dataSet.Tables[0].Rows)
{
token = ((string)row["Token"]);
lemma = ((string)row["Lemma"]);
...
//// TODO: ex. write to file
}
but, I have a class that it demonstrate this stored objects.
a class like this:
public class Lexeme
{
private int tokenId = -1;
private string token;
private string lemma;
/// some get and set functions!
}
as you see this class holds an object (it's something like a wrapper for stored object inside of database tables)
So I want to know is there anyway to return a list of this object (Lexeme here) instead of dataset? I mean something with efficient memory usage. because i work with huge amount of data.
for example something like this:
public MYDATASET CollectData()
{
MYDATASET result = new MYDATASET ();
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand("dbo.StoredProc1", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
IDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(result);/// filling a dataset
return result;
}
}
dataset can be inherited?
You can use a Typed Dataset instead of your own object. This allows you to fill a dataset easily, but also have strongly typed columns and the ability to access each property easily within a row. Go to the Add New Item window of Visual Studio and add a Dataset. Add a new table using the designer, and add the columns that are being returned from your sql query. Go to the properties window on each column and specify the type (int, string, etc).
From there, when you're loading the dataset, create a new object of your dataset type, and fill it like you were before:
public MyTypedDataset GetMyDataSet()
{
MyTypedDataset ds = new MyTypedDataset();
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand("dbo.StoredProc1", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
IDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(ds.Table1);
return result;
}
}
With a typed dataset there is a property for each table item you created in the designer. (By default I believe it is named Table1?)
Now, when accessing your data, you can do
MyTypedDataset ds = GetMyDataSet();
string myToken = ds.Table1.Rows[0].Token;
string myLemma = ds.Table1.Rows[0].Lemma;
Or in a foreach:
MyTypedDataset ds = GetMyDataSet();
foreach(var row in ds.Table1)
{
string myToken = row.Token;
string myLemma = row.Lemma;
}
This isn't quite as good as getting a list of your object back, but it's almost there. If you want a list of your own object, you'll most likely need to use an Object Relational Mapper, such as Entity Framework or NHibernate.
Related
I am retrieving particular column value using DataSet.
This is my code:
public DataSet GetRedirectURL(string emailId)
{
DataSet ds = new DataSet();
using (SqlConnection con = new SqlConnection(#"Connection_String_Here"))
{
con.Open();
SqlCommand sqlComm = new SqlCommand("usp_Login", con)
{
CommandType = CommandType.StoredProcedure
};
sqlComm.Parameters.AddWithValue("#EmailId", emailId);
SqlDataAdapter da = new SqlDataAdapter
{
SelectCommand = sqlComm
};
da.Fill(ds);
}
return ds;
}
I have also used DataTable instead of it but the same result.
I have checked my Stored Procedure and when I pass Parameter it shows Data. So, nothing wrong with the SP. But the Table doesn't show any data and is always empty as shown below:
What am I missing? Any help would be appreciated.
I'd suggest you to first evaluate the content of your DataSet. For instance, type in your Immediate Window (or add a quick watch) to check ds.Tables[0].Rows.Count. Basically, to assert your DataSet has been properly filled with the contents fetched from the database, and focus on the data assignment from the DataSet to the grid object you're using to display it.
Also, the .Fill() method has a returning object which is an int representing the amount of rows that have been successfully filled into the target object. For instance:
int result = da.Fill(ds);
Check the value of result after the .Fill() method has been executed.
Finally, I guess you're using a DataGridView object to visualize the results. If so, how are you binding data? Should be something like:
dataGridView1.DataSource = ds.Tables[0];
PS: As I've read in other comments, no, you don't need to execute the .Open() method on the connection. That's not necesarry, it's done implicitely when using the (using SqlConnection conn = SqlConnection..)
I don't know my title is understandable but actually I want to know which one is better?
1-Creating object class and get data from mssql db with loop
2-Getting data from sql db with json format
3-Something else..
I think, loop can be slow when working with big datas. However maybe using json path can be slower than loop.
Example for 1 (CREATING OBJECT IN LOOP)
List<objExample > retVal = new List<objExample >();
objExample item;
SqlConnection con = new SqlConnection("CONNECTION STRING");
SqlDataAdapter da;
SqlCommandcmd;
da = new SqlDataAdapter("Select a,b from table", con);
con.Open();
DataTable dt = new DataTable();
da.Fill(dt);
con.Close();
foreach (DataRow itemdr in dt.Rows)
{
item = new objExample();
item.A= itemdr["a"].ToString();
item.B= itemdr["b"].ToString();
item.HasError = false;
retVal.Add(item);
}
return retVal;
Example for 2 (FOR JSON PATH)
List<objExample > retVal;
SqlConnection con = new SqlConnection("CONNECTION STRING");
SqlDataAdapter da;
SqlCommandcmd;
da = new SqlDataAdapter("Select a,b from table for json path", con);
con.Open();
DataTable dt = new DataTable();
da.Fill(dt);
con.Close();
string _json = dt.Rows[0][0].ToString();
retVal = JsonConvert.DeserializeObject<List<objExample>>(_json);
return retVal;
I tried both of them with small data but it didn't satisfy me.
PS : I wrote codes in my mind. Sorry about wrong codes and bad English.
Please guide to me. Thanks.
Just to be clear, are you reading the complete table?
If the goal is to get data that is stored within the json, and maybe perform some queries on it a NoSQL DB seems more appropriate that a SQL one.
Count the number of commands that are dependent on the number of rows. Kind of how we do the Big O Complexity.
I would do something like:
using (var sqlCommand = new SqlCommand("Select a,b from table for json path", con))
{
try
{
using (var reader = sqlCommand.ExecuteReader())
{
while (reader.Read())
{
item = new objExample();
item.A= reader["a"].ToString();
item.B= reader["b"].ToString();
item.HasError = false;
retVal.Add(item);
}
}
}
}
Keep in mind that the sql connection will remain open while you are doing this so its judgement call if you want to do this after loop or in the loop.
And the da.Fill or using the above is same internally, still going to iterate over all rows.
As far as using json is concerned, I wouldn't do that unless you are asking if storing as Json file is a better option than in sql. That's a whole diff question.
You can use PLINQ to process the data in parallel once you have it in the list, even for your above deserialization you can try PLINQ.
I have a task to develop a console application that is a recon of values from a few tables in the DB. I have all the queries that I need for each value that is required and understand the logic on how the values will interact. The challenge I have is the best method to retrieve and store these values.
I have researched and successfully been able to create the static method to retrieve a single value from a single SQL query but I'm curious about the best method:
Create multiple methods to retrieve each value (upwards of 15 different select statements) summarised below (not complete code)
static double total1(int arg)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command1 = new SqlCommand(commandText1, connection));
return(response);
}
}
static double total2(int arg)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command2 = new SqlCommand(commandText2, connection));
return(response);
}
}
Try to combine all select statements in a single method (I've been unsuccessful here) summarised below (not complete code)
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command1 = new SqlCommand(commandText1, connection))
{
}
using (SqlCommand command2 = new SqlCommand(commandText2, connection))
{
}
// etc
}
Create stored procedures in SQL and execute them and pass the parameters via the c# console app
I think method 1 is going to be taxing on the server as it would require the connection to open and close multiple times (although I don't know if that's as big a issue as I think it is). Method 2 seems more reasonable although I've followed the concepts here and I get stuck when trying to get the output of the commands (I'm using return). Method 3 seems smarter to me although I'd still be in a position where I need to choose between methods 1 & 2 to execute the SP's.
I would really appreciate advice and guidance here, I'm new to C# so this is a steep learning curve when tutorials don't cover the sort of thing (or at least I can't define my problem properly)
string query = "SELECT * FROM table1;";
query += "SELECT * FROM table2";
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(query))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.Connection = con;
sda.SelectCommand = cmd;
using (DataSet ds = new DataSet())
{
sda.Fill(ds);
}
}
}
}
I've recently seen that this question is still being viewed so I'll post the solution for anyone who is just starting off developing and encounters a similar challenge.
The most suitable solution was to create a stored procedure, pass each unique argument to it and return all the relevant data in a single response to the application. A custom model was defined for this output and the application logic adapted accordingly. The result is a longer running single call to the database as opposed to multiple individual ones.
Using the format from the question, the solution was:
C# code
static NewModel AllTotals(int arg1, int arg2)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
var commandText = "TheStoredProcName";
SqlCommand command = new SqlCommand(commandText, connection));
command.CommandType = System.Data.CommandType.StoredProcedure;
Cmd.Parameters.AddWithValue("#arg1", arg1);
Cmd.Parameters.AddWithValue("#arg1", arg2);
using (SqlDataReader dr = Cmd.ExecuteReader())
{
while (dr.Read())
{
var response = new NewModel(){
Value1 = Convert.ToDecimal(dr["value1"]),
Value2 = Convert.ToDecimal(dr["value2"]),
};
return(response);
}
}
}
return null;
}
SQL Stored Proc
CREATE PROCEDURE [dbo].[TheStoredProcName]
#arg1 int,
#arg2 int
AS
DECLARE #value1 decimal(18,6) = ISNULL((--QUERY TO GET VALUE1),0)
DECLARE #value2 decimal(18,6) = ISNULL((--QUERY TO GET VALUE2),0)
-- select the variables into a result set for the application
SELECT #value1 as [value1], #value2 as [value2]
This is basically a search tool. When I type some thing in a combobox, the combobox drops down and will show me suggestions (something like Google search bar)
I created a procedure which does some complex calculations, which take one parameter and returns some rows. Then I created a combobox event (On Update Text).
And in the event handler I wrote this code:
private void combobox_TextUpdate(object sender, EventArgs e)
{
this.combobox.Items.Clear();
DataTable List = new DataTable();
if (this.combobox.Text.Length > 0)
{
List = searchIt(combobox.text);
foreach (DataRow Row in List.Rows)
{
this.combobox.Items.Add(Row.ItemArray.GetValue(0).ToString());
}
this.combobox.DroppedDown = true;
}
}
static public DataTable searchIt(string STR)
{
string connectionString = McFarlaneIndustriesPOSnamespace.Properties.Settings.Default.McFarlane_IndustriesConnectionString;
SqlConnection con = new SqlConnection(connectionString);
DataTable DT = new DataTable();
con.Open();
SqlDataAdapter DA = new SqlDataAdapter("USE [McFarlane Industries] " +
"EXEC search " +
STR, connectionString);
DA.Fill(DT);
con.Close();
return DT;
}
The function searchIt executes the stored procedure and it returns a DataTable. The stored procedure is working fine in SQL Server Management Studio.
But in the application it is not working correctly in some cases.
When I type [space], then it throws an exception and it says stored procedure needs parameter which is not provided.
There are many other characters when I type them it throws exception that invalid character at end of string "my string".
Any suggestion how could I achieve my goal.
Call your stored procedure with sqlcommand to fill your datatable
using (SqlConnection scn = new SqlConnection(connect)
{
SqlCommand spcmd = new SqlCommand("search", scn);
spcmd.Parameters.Add("#blah", SqlDbType.VarChar, -1); //or SqlDbType.NVarChar
spcmd.CommandType = System.Data.CommandType.StoredProcedure;
using (SqlDataAdapter da = new SqlDataAdapter(spcmd))
{
da.Fill(dt);
}
}
static public DataTable searchIt(string STR)
{
string connectionString = McFarlaneIndustriesPOSnamespace.Properties.Settings.Default.McFarlane_IndustriesConnectionString;
SqlConnection con = new SqlConnection(connectionString);
DataTable DT = new DataTable();
con.Open();
SqlCommand command = new SqlCommand("Name_of_Your_Stored_Procedure",con);
command.CommandType=CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#parameter_name",SqlDbType.NVarChar));
command.Parameters[0].Value="Your Value in this case STR";
SqlDataAdapter DA = new SqlDataAdapter(command);
DA.Fill(DT);
con.Close();
return DT;
}
Important :
'parameter_Name' and 'Name_of_Your_Stored_Procedure' should be replaced by yours which you have in database. And value of parameter could be like "abc" (combox.Text)
Command and its type, its text are necessary.
Adding parameters depends upon your stored procedure. They can be 0,1 or more but once they are added their values must be given. conn(connection) can be passed to new SqlCmmand() or new SqlDataAdapter()
No need of things like 'use' and 'exec'
Following me and this link might be helpful in future for stored procedures
http://www.codeproject.com/Articles/15403/Calling-Stored-procedures-in-ADO-NET
Two optional Suggestions for you
use variable name 'list' instead of 'List' (you used) however you will not get problem with this name until you add a namespace using System.Collections.Generic; but you may need to use this namespace in future.
Use only list.Rows[0].ToString(); no need to get itemarray then get value when you are working with data in strings;
I'm wanting to convert the line to C# from VB6 and am having quite the difficulty doing so.
VB6 Code:
txtFields(4).Text = rsGroup.Fields(0).Value + 1
C#: (what I have so far)
txtFields4.Text = (rsGroup.Fields[0].Value) +1);
What is the correct way to do this?
#jdurman,
An example of retrieving data using a DataSet is:
public DataSet GetDate(string SqlString)
{
SqlConnection sqlConn = new SqlConnection("CONNECTION STRING GOES HERE");
DataSet ds = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter(SqlString, sqlConn);
adapter.Fill(ds);
return ds;
}
public void LoopThroughDataExample(DataSet ds)
{
foreach(DataTable dt in ds)
{
foreach(DataRow dr in dt)
{
Console.WriteLine(String.Format("Value is: {0}", dr["DBColumnName"])); // Replace DBColumnName with the name of columns in the Database Table that you want to Extract.
}
}
}
I would not use a RecordSet and Use a DataSet instead.
you can use the System.Data.SqlClient namespace to be able to access Databases and then you can bind controls from your DataSet, makes life alot easier, and also i would avoid doing straight copying of code from VB6. There is alot of new thing in the world of C# that you would never of had the option of using in VB6 prior.
txtFields[4].Text = rsGroup.Fields[0].Value + 1;