I'm new to using C# in Visual Studio 2010, so my knowledge is fairly limited.
I am looking to make a program that runs and exports multiple Stored Procedures in SQL Server 2008 - also with a nice interface.
The thing I am unsure about is how this is best done?
I was thinking that I want a form with maybe a treeview and a datagridview and then execute the stored procedures. This works fine with just one query - but my question is how this is done best with multiple querys? I don't want different datagridviews for each stored procedure (I have a lot). I want to be able to select a different stored procedure in my treeview and have the data in the datagridview to change without having to run the Stored Procedure every time. Some of them are pretty timeconsuming (> 1 min). So I quess what I am asking is, if I can somehow load all the data into my program at once?
Can I get a dataset to hold more than one table - or will I somehow have to create different datasets for all my stored procedures?
Rather than load all the data into the program at once, what you want is to cache the results of a query the first time you run it. This stops people having to wait for everything to load just so they can look at one data set.
Your scenario as you describe it at the moment is that when you click a particular item in the tree view, the relevant SQL is run and the collection of results is bound to your datagridview, wiping out any previous data.
The practice of caching inserts a get-if-I-don't-already-have-it layer and a method of storing. Something like this:
public class MyResultClass
{
public string Column1 { get; set; }
public string Column2 { get; set; }
}
private static readonly Dictionary<string, IEnumerable<MyResultClass>>
CachedResults = new Dictionary<string, IEnumerable<MyResultClass>>();
protected void OnTreeViewSelectionChanged(object sender, EventArgs e)
{
// I'm not overly familar with the treeview off the top of my head,
// so get selectedValue however you would normally.
var selectedValue = ????;
IEnumerable<MyResultClass> results;
// Try to find the already cached results and if false, load them
if (!CachedResults.TryGet(selectedValue, out results))
{
// GetResults should use your current methodology for getting the results
results = GetResults(selectedValue);
CachedResults.Add(selectedValue, results);
}
myGridView.DataSource = results;
}
Note: If this is a web application rather than a winforms one, you'll need to use a ConcurrentDictionary instead of a Dictionary to make this pattern thread safe.
Related
I have an object in my SQL Server database that is called dbo.stringlist
CREATE TYPE [dbo].[StringList] AS TABLE
(
[Item1] [varchar](2000) NULL
)
I have a stored procedure that has syntax in SSMS like
exec [dbo].[Getdata] #Fields
(which is the dbo.stringlist) which effectively just joins on a table in the stored procedure and acts as a long list of criteria. It's how I want to deal with the request on the database side, so I won't be changing that.
All I want to do is execute this in C# (hopefully) using Dapper, because the rest of the goal has been built out using nothing but Dapper. I can scrap it if need be. The goal is to effectively write an ETL of sorts, but instead of endpoint-to-endpoint SSIS-like packages, I am just automating deploy scripts for new builds.
If there is a way to do this outside of Dapper that is easier, then I am all for scrapping this at this point. Like I said, the documentation for this is sparse, at least the updated documentation for this specific task is sparse.
I tried this method - https://gist.github.com/taylorkj/9012616
And also tried this method - https://bornsql.ca/blog/table-valued-parameters-and-dapper-in-net-core/
The second one didn't work, because I just want to pass the list in, but that's not an option. It needs to be an IEnumerable, which I don't feel like I can pass values into like a list. But maybe I just don't know what I am doing when it comes to that interface.
So if anyone has an UP-TO-Date link to help me out that would be stellar. I have a feeling I am going to have to scrap everything I have done, which is fine, I guess. I just want the tool to work. I know this post doesn't have a lot of information, that's why I am just asking for ideas to accomplish what I am trying to do in C# and hopefully Dapper, but like I said, I am not married to it.
I got it to work with the second link.
private static IEnumerable<SqlDataRecord> CreateSqlDataRecord(IEnumerable<string> list)
{
var metaData = new SqlMetaData("Item1", SqlDbType.VarChar, 2000);
var record = new SqlDataRecord(metaData);
foreach (var item in list)
{
record.SetSqlString(0, item);
yield return record;
}
}
public static SqlMapper.ICustomQueryParameter GetTableValuedParameter()
{
string[] list = new string[] { };
return CreateSqlDataRecord(list).AsTableValuedParameter("dbo.StringList");
}
I wasn't updating the parameter nor was I including a varchar data length of 255.
I have a C# WinForms program accessing SQL server and querying data from it. I have two main classes: Users which contains the datatypes for the users that can log into the app, and Products which contains again the datatypes for the products that can be queried. Also I have a class that holds the methods for accessing the sql server. I made a function querying the users form the sql database into a list which than I load into a ListView lsv_MangageUsers. I was able to create the add new user and delete method, but when I started creating the modify user method I ran into a problem. Visual Studio says:
"Cannot convert type 'System.Windows.Forms.ListViewItem' to 'my app.Users' class".
I tried giving the selected item's value casting in Users class to the modify method and load into a new forms controls to allow the user to make modification on it. If I used method and function in a wrong order my apologies I am still new in C#. Any help would be appreciated.
The button's code that running the modify user method:
private void btn_ModifyUser_Click(object sender, EventArgs e)
{
if (lsv_ManageUsers.FocusedItem.Index != -1)
{
UserNew userwindow = new UserNew((Users)lsv_ManageUsers.SelectedItems[0]);
if (userwindow.ShowDialog() == DialogResult.OK)
{
LsvUsersRefresh();
toolStripStatusLabel1.Text = "User successfully modified!";
}
}
}
The item referenced by lsv_ManageUsers.SelectedItems[0] is a ListViewItem, it is not one of your Users items, and you can't just cast from one to another because they are completely different things.
If you want the world to work in this way then each ListViewItem has a Tag property that you are free to use for whatever purpose you feel like. Suggest adding the Users item to this property when you add the ListViewItem to the list, and then you can dereference it within your click handler.
I have an asp.net 4.0 c# web application. I am using listview and formview controls with templates on my forms. I am trying to control the maxlength property of my bound textboxes without hard coding the field sizes into my aspx pages. I would like to when I first load the application fill some kind of local object or array with the column lengths of my fields and then use those values to dynamically set the maxLength field of textboxes.
There are so many methods out there to try and I am not sure what is the most efficient.
My sql to get the schema info is
SELECT TOP (100) PERCENT sys.sysobjects.name AS TableName, sys.syscolumns.name AS ColumnName, sys.systypes.name AS DataType,
sys.syscolumns.length
FROM sys.sysobjects INNER JOIN
sys.syscolumns ON sys.sysobjects.id = sys.syscolumns.id INNER JOIN
sys.systypes ON sys.syscolumns.xtype = sys.systypes.xtype WHERE (sys.sysobjects.xtype = 'U') AND (sys.systypes.name <> 'sysname')
ORDER BY TableName, sys.syscolumns.colid
how can i store this locally so I don't have to keep querying the server and I can I set this dynamically using c#
I am a semi newbie so as much detail as can be provided would be appreciated.
See you are getting the column lengths from the database, now you need to do this txtBox.MaxLength.
Doing this dynamically can be avoided if you already design your aspx pages tightly coupled with database tables.
But if you are sure you want to go this way then:
1.) On application start up fetch all the values from the DB and make a dictionary cache out of it, it will sit in memory as long as the application is up.
2.) Now, on each page load you need to read those values from the dictionary and use TextBox.MaxLength property to set the values. This way you are adjusting the max length property before it is delivered to the client machine.
Thats it !!!
Anyways, any approach of this sort will bring down application performance. Consider pre-designing aspx pages.
There are two main ways of doing this, static variables (essentially global variables) or using the application cache. Personally I prefer static variables as I find the API for System.Web.Caching to be over-complicated.
This is how you use static variables with a bit of a discussion on which is the best method (including how to use the new Lazy class in .Net 4.0+):
Why use System.Runtime.Caching or System.Web.Caching Vs static variables?
This is how to use System.Web.Caching:
http://msdn.microsoft.com/en-us/library/system.web.caching.cache.aspx
I wouldn't worry too much about which is more efficient, the methods of doing this are almost identical performance wise.
Thanks for your suggestions. For my purposes I just kept it simple because this is a relatively small app.
Since I am using templates I have the same field defined multiple times in many places. Since my application data fields will be changing not infrequently, this just gives me one place in the application to change the maxLength property.
in my aspx page:
' MaxLength="<%# TableSchema.SomeField1Length%>" />
I made a class
public static class TableSchema
{
public static int SomeField1Length
{
get { return 15; }
}
public static int SomeField2Length
{
get { return 100; }
}
public static int SomeField3Length
{
get { return 15; }
}
}
It's seems to be working ok. I have to see if this causes a performance hit.
I need a data structure of some sort to do the following:
One "set" composed of many types such as string, integer, datetime and double.
Many sets are added dynamically
The sets are retrieved dynamically where information is pulled
Now the obvious solution is to use a DataTable. Define the datatable structure, and add a new row each time you need to add a new set. Pull data from the datatable when you need to.
Actually I have implemented it already using a datatable, but the problem is it is extremely slow for some reason. Since this is done thousands to millions of times performance can be problematic.
Is there an alternative datatable type of data structure with better performance that I can use or should I build my own class using Lists<> ?
Depending on your use case I would recommend using List<object[]> (since you mentioned dynamic schema) as central data structure, but you will need to maintain the schema info yourself if you need it later on.
If you need to bind the UI to the data this approach will add a lot of extra manual work, it's better suited for background processing of large amounts of data.
We have used this approach in the past and were able to save 2/3 of memory and 80% of execution time when bulk handling data compared to data tables.
One alternative way of approaching problems like this: use a sqlite database in memory.
Sounds like a weird thing to do at first, but you can put quite complex structures into tables, and you get the whole power of SQL to work on your data. SQLite is a tiny lib, so it won't bloat up your code. Integrating the DB into your code might be kinda strange at first, put performance should work on huge data sets (since that's what DBs are made for). And if you ever need to save that data to disk, you are already done.
Depending on the details of your problem, it might even be a good idea to move to a bigger db back end (e.g. postgres), but that is hard to tell from here. Just don't dismiss this idea too easily.
There are several similar questions on stackoverflow, but none provides a good answer. A generic alternative should not be List<YourObject>, because YourObject is not generic. The beauty of DataTable is that it does not have a data model.
A DataTable is a collection of rows, while each row is a collection of cells. A cell could be a string or a number. So we can define a Cell as:
public class Cell
{
public double Value { get; set; }
public string Text { get; set; }
}
Then a row would be Dictionary<string, Cell>, where string is the column name. And then a DataTable alternative is simply a List<Dictionary<string, Cell>>.
Let's say you define Rows as public List<Dictionary<string, Cell>> Rows;.
Now you can easily query the Rows like:
var MaleHeight = Rows.Where(row => row["sex"].Text == "Male").Select(row => row["Height"].Value);
When creating Winforms application using .NET 4, I constantly find myself writing this type of code:
public partial class StudentListerForm : UserControl
{
public StudentListerForm()
{
InitializeComponent();
LoadBranding();
}
private void StudentListerForm_Load(object sender, EventArgs e)
{
cmbGrade.DisplayMember = "Name";
cmbGrade.ValueMember = "GradeId";
cmbGradeInstance.DisplayMember = "Name";
cmbGradeInstance.ValueMember = "GradeParaleloId";
LoadExistingGrades();
}
private void LoadExistingGrades()
{
GradeRepository repo = new GradeRepository();
cmbGrade.DataSource = repo.FindAllGrades();
}
That's just an excerpt. The point is, how can I more cleanly display data retrieved from a database? I find myself changing something in the schema and having to go one by one column checking if the name is correct.
Or am I being just paranoid.
It's a question of mapping really. If you have the database column name mapped through to each control then yes, if you change that coloumn name you will need to update the code to reflect that change. This isn't the best approach as it means your front end code is mapped directly onto your database unless you're using MVC. I'd recommend you look at two things.
Firstly, why are you changing names of database columns in the first place? Has the column changed in purpose? Should it be a new column entirely?
Secondly, can you use stored procedures, views or some sort of dataset mapping in between the database and the front end? That way, if the database column does change name, you only need to change it in the stored procedure/view/dataset and your front end wouldn't be coupled to the old name.