I have been struggling with this bit for over a day now. It appears that many people have asked about similar thing, but they usually want to do something way more advance than what I need. I got an idea what it should look like (I think), but struggle with actually properly implementing it - so here it goes:
I have a form application that does some Odbc, Sql, Csv import/exports.
My main class is the ImportForm class, which contains all the buttons, controls it also creates SQL and ODBC connections in each constructor etc.
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
ImportForm importForm = new ImportForm();
Application.Run(importForm);
}
.
public partial class ImportForm : Form
public static SqlConnection sqlConnection = new SqlConnection(ConstantValues.SqlConnectionString);
public static OdbcConnection odbcConnection = new OdbcConnection(ConstantValues.OdbcConnectionString);
(...)
I now have few other classes that do different things. For instance once of imports CSV files into SQL Server. It does it through SqlBulk based on the SQL connection defined in the ImportForm class:
internal class CsvImportIntoSql
SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(sqlConnection);
This, however, returns a syntax error 'The name does not exist in the current context'
I tried:
SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(importForm.sqlConnection);
But it doesnt work, the class ImportForm is available in the context, but its defined instance importForm is not and I cannot understand why and what I should do to make it work - I have been struggling with that for a while and have to employ different workarounds which often do not make for good code.
Any help would be appreciated.
Almost right: you need the class name ImportForm, not an instance of it ( importForm) to access a static property:
SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(ImportForm.sqlConnection);
If the CsvImportIntoSql instance is created in the ImportForm, then your best option would be to inject the sqlConnection, or if it is likely to change after the CsvImportIntoSql instance is created then inject a refrence to the CsvImportIntoSql instance itself.
If I understand, you are trying to use the same sqlConnection variable that is defined in another class. but it appears that you have declared this variable as static, which should help while referring to it from another class:
Try to replace
SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(sqlConnection);
with:
SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(ImportForm.sqlConnection);
This should work. however,using the same connection in multiple instance is not always a good practice. instead, you can initialize a new connection for each job.
Related
I'm not sure if I'm being clear in the title but I'd like to "load" information from a SQL Server database into a list of objects. I'm new to c# and honestly haven't done any coding in a while.
Essentially the table would have columns: app_name, app_type, app_disposition and the object has properties: name, type, disposition. I've got what I want working using Dapper and simply making the object properties the same as the table columns.
Just curious if you could load but using different object property names.
With Dapper, simplest solution is to use aliases.
Your class is:
public class MyPoco
{
public string Name {get;set;}
//Declare other properties here
}
And, you fill this class as below:
string sql = "SELECT app_name as Name, [include other columns here]
FROM MyTable";
using (var conn = GetOpenConnection())
{
var myPocoList = conn.Query<MyPoco>(sql);
}
GetOpenConnection method above simply returns open connection depending on your RDBMS.
Please note that there are many other ways to map the miss-matching column and property names. Please refer this Q&A for more details.
Yes, you can, and you have to use the "Custom Mapping" feature. Here's a detailed article I wrote on the subject, along with code samples, to shows how you can do it.
https://medium.com/dapper-net/custom-columns-mapping-1cd45dfd51d6
Hint: Use Dapper.Fluent-Map plugin
I'm quite new here, so please forgive me if I made any deviation from the rules of this website.
I'm trying to find the best way possible to manage the names of a stored procedure in code.
Currently when I'm calling a stored procedure I'm using this code:
public static DataSet GetKeyTables()
{
DataSet ds = new DataSet();
ds = SqlDBHelper.ExecuteMultiSelectCommand("Sp_Get_Key_Tables",
CommandType.StoredProcedure);
return ds;
}
But I don't think that stating the name of the stored procedure in code is a wise idea, since it will be difficult to track.
I thought about Enum or app.config solutions, but I'm not sure these are the best ways.
Any idea will be highly appreciated.
You can have a class with constant properties having names of the SPs.And have this class in a seperate class library (dll). Also it is not good to have sp_ as start of procedure see the link http://msdn.microsoft.com/en-us/library/dd172115(v=vs.100).aspx
public class StoredProcedures
{
public const string GetKeyTables = "Sp_Get_Key_Tables";
}
In the end, it always boils down to the concrete name string of the SP, no matter what you do. You have to keep them in sync manually. - No way around it...
You could use configuration files for that, but that additional effort will only pay when the names change frequently or they need to remain changeable after compilation.
You can wrap the calls in a simple gateway class:
public static class StoredProcedures
{
public static DataSet GetKeyTables()
{
return SqlDBHelper.ExecuteMultiSelectCommand(
"Sp_Get_Key_Tables",
CommandType.StoredProcedure);
}
public static DataSet GetFoobars()
{
return SqlDBHelper.ExecuteMultiSelectCommand(
"Sp_Get_Foobars",
CommandType.StoredProcedure);
}
}
Alternatively you can have POCOs that know how to interact with the database:
public class KeyTable
{
public int Id { get; set; }
// whatever data you need
public static List<KeyTable> GetKeyTables
{
var ds = SqlDBHelper.ExecuteMultiSelectCommand(
"Sp_Get_Key_Tables",
CommandType.StoredProcedure);
foreach (var dr in ds.Tables[0].Rows)
{
// build the POCOs using the DataSet
}
}
}
The advantage of this is that not only the SP name is kept in a unique place, but also the logic of how to extract data out of the dataset is in the same place.
I don't see a huge issue with what you are doing. You would need to store the SP name somewhere, so either in the query or in another config or helper function.
Depending on the specification, I tend towards a repository for CRUD operations, so I know all data access, including any SP calls, are in the ISomeRepository implementation.
When I work with stored procedures in C# I follow the following rules.
Every stored procedure is used only once in the code so that I have
only one place to update. I do hate Magic strings and avoid
them but stored procedures are used in Data Access Layer only once (e.g. Repositories, ReadQueries, etc).
For CRUD operations the pattern "sp_{Create/Read/Update/Delete}{EntityName}" is used.
If you want to have single place with all your stored procedures, you can create a static class with logic to create stored procedure's names.
I am using VS 2010 and C# windows forms.
I need the user to enter how many objects he has and how much each weights.
I then need to process each one. I typically use for each datarow in row collection.
Question is i tried cleaning up some of my Very Nasty code (this is my first real project ever btw) I have one main class at ~5000 lines of code and would like to break up specific sets of modules into there own classes. The problem is when the user enters info i have to set up a dataset on the main form (DSObjects) and link a table grid view and a couple of entry boxes with an add button to it so the user can add the data they need. The issue I am having is when I run the code and break up the class into sub classes the dataset is wiped out on each new class.
Do not create a new instance of the data set in every class, but pass one instance around, like:
public class AnotherClass
{
private DataSet m_dataSet;
public AnotherClass(DataSet ds)
{
m_dataSet = ds;
}
}
When creating a new instance of AnotherClass use:
AnotherClass ac = new AnotherClass(m_dataSet);
where m_dataSet is again a member variable that references the data set - either passed to the calling class in the constructor, or (in case of the main class) being created somewhere in the code.
Only create the data set once, for example in the main class.
Another approach could be to use a singleton class that holds an instance to the data set. The singleton could then be accessed from lots of different objects.
A non-threadsafe sample would be:
public class DataHolder
{
private DataSet m_dataSet;
private static DataHolder m_instance;
private DataHolder()
{
m_dataSet = ... // Fill/Create it here
}
public static DataHolder Instance
{
get
{
if (m_instance = null)
m_instance = new DataHolder();
return m_instance;
}
}
public DataSet Data
{
get { return m_dataSet; }
}
}
Then, access it using DataHolder.Instance.Data;
You could try passing the dataset into the constructor of each class
var something = new Something(dataset)
Keep in mind that a DataSet is actually a small (but complete) database in memory. While most applications just use it to transfer data from a database server to objects in the application, it has all the parts of a full database: multiple tables, which can be joined be relationships, which can have queries run against them.
With that in mind, just as you wouldn't have separate databases for each class, but instead have one used globally for the whole application, it is similarly quite reasonable to have one DataSet shared by all objects in the application.
Here is my sample code:
public static class MySqlHelper
{
private static string constring = ConfigurationManager.ConnectionStrings["MyConnString"].ConnectionString;
public static int ExecuteNonQuery(string mysqlquery)
{
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(mysqlquery, conn);
int result;
try
{
conn.Open();
result= cmd.ExecuteNonQuery();
}
finally
{
conn.Close();
}
return result;
}
}
Usage: MySqlHelper.ExecuteNonQuery("select * from customers");
I would like to know the issues using this static class.
I can change my class as mentioned here but I have been using this class in couple of websites and I will need couple days to change it in every place and test it out.
Thanks for any inputs.
Edit: Updated the code. Does that make difference on the answers provided? Sorry, I should have posted in the beginning.
I am assuming the connection string doesnt change during execution (you might want to make it readonly). Since there is no other shared state shown in the question, there are no real problems.
However, if you have any shared state you have a huge threading problem. And if you have shared connections you have an even bigger problem.
But as written, with no significant static fields: no problem.
I thought he was pretty clear on his answer.
Writing my own Provider Class in ASP.NET
"remember that the connection will be shared at the same instance for all users, which can cause bad problems..."
Static classes are difficult to test.
Your question mentions that for a change you'll have to change the class on a couple websites. If your websites were coupled to an interface, then swapping out the implementation would be relatively simple.
In my own projects I avoid public static classes. They can get unwieldy very quickly.
As such no issue it depends how you are using this class, ideally it part of abstract factory pattern to have static connections so that same connection can be used all over application, but having methods such as executereader and other mthods is not a good choice. similarly always check that connection has not been closed or its state before its usage, because if you are having static connection and you used using syntax with executereader then it will close the connection and if some other method used connection after this then it will get the error
The obvious drawbacks are:
hardcoded connection string
without connection pooling in the driver this is very bad: //open conn + //close conn
1) can be ugly solved by using a singleton as the connection string name
2) cannot be solved in a static class without introducing shared data: ie. without planting a knife in your back.
Do you know that the MySQL Connector for .NET now has a MySqlHelper class (you can check it in the source here)?
If you are going to take this route you many want to consider using the Microsoft DAAB SqlHelper v2 offering. It uses the same concept but is much more robust. It also caches SqlParameters. The code came out circa 2001 and has been in constant use by many developers.
http://www.microsoft.com/download/en/details.aspx?id=435
I'm trying to learn this tutorial http://www.devx.com/dotnet/Article/28678/1954 in C#, I have created the datatables but when I want to type
DsActivitiesTasks.Tasks.AddTasksRow("Email")
Intellisense doesn't see Tasks but only TasksRow and TasksDataTable and none have add method.
Did I forget to do something ?
DsActivitiesTasks is the name of the class generated by the designer.
Tasks is an instance property of that class, so you can only access it from an instance of the dataset.
Try creating a new instance of DsActivitiesTasks, like this:
new DsActivitiesTasks().Tasks.AddTasksRow("Email");
Note that this code will throw away the new dataset; you'll need to store it somewhere in a field or property.
For example:
public static readonly DsActivitiesTasks Database = new DsActivitiesTasks();
//In some method:
Database.Tasks.AddTasksRow("Email");
Note that datasets are not thread-safe, so you must not work with it on multiple threads.
Instantiate DsActivitiesTasks.