i have a Class called "Services" in the App_code folder that contain Method like this:
public static ???? GetAllCustomers()
{
string conn = ConfigurationManager.ConnectionStrings["ConnectToDB"].ConnectionString;
using (SqlConnection connection= new SqlConnection(conn))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "select C_ID,L_ID,C_Name from Customer";
cmd.Connection = connection;
connection.Open();
????
????
}
}
return ???;
what should i use in the "????" as return type...because i want to bind dropdownbox.datasource to ???? and use the datavaluefield and datatextfield..
so should i make the method return datatable class or something else..
i hope i made my question clear..
You can return a System.Data.DataTable and use column names for datatextfield and datavaluefield.
If you're going to write it with so much specificity (i.e., it's tailored to one specific dropdown, not abstracted to the point that it can be used by any other dropdown), then instead of a function, make it a sub (void? -- no return type in any case). There's only two addtional steps to add then -- set the dropdown's datasource, and then call databind.
So then, you'd just call the sub each time you wanted to populate the dropdown.
If you want to abstract it a little more, so that it takes parameters for commandtext, or what have you, then a function would be a good idea. In that case, datatable would be a good return type.
Related
I came across the followng code in the code behind and wondering
if this may be a good practice in terms of inserting a record
programmatically:
protected void ButtonMain_Click(object sender, EventArgs e)
{
string sConn = ConfigurationManager.ConnectionStrings["SQL1"].ConnectionString;
SqlDataSource dbQ = new SqlDataSource();
dbQ.ConnectionString = sConn;
dbQ.InsertCommand = "INSERT INTO data1_DropDownLists (ParamID, ddlValue) VALUES ('" + ddlAllParams.SelectedValue + "','" +
txtddl.Text + "')";
dbQ.Insert();
DropDownGrid.DataBind();
dbQ = null;
}
What I have seen is before is something like:
string query = "INSERT INTO data1_DropDownLists vALUES ...";
cmd = new SqlCommand(query, conn);
conn.Open();
cmd.ExecuteNonQuery();
so was not sure of what the benefit may be to using the above method using InsertCommand
The SqlDataSource is a control in the System.Web namespace. It can be used as datasource for web-databound controls like Repeater or GridView.
It is a control which should be used declaratively on the aspx markup and not in codebehind. It's like an interface between the GUI and the DAL. Normally you should avoid this kind of hardlinking. Instead you should separate GUI(ASPX), BLL(codebehind or class libraries etc.) and DAL (ADO.NET or Entity framework etc.).
I would suggest to use the most direct way, using an ADO.NET SqlCommand:
// use using-statement to ensure that the connection gets closed even in case of an error
using (var con = new SqlConnection(connectionString))
{
using (var cmd = new SqlCommand("INSERT INTO dbo.Table(Column)VALUES(#Column)", con))
{
// use parameters to avoid SQL-Injection
cmd.Parameters.AddWithValue("#Column", value);
con.Open();
cmd.ExecuteNonQuery();
}
}
The SqlDataSource class has four command properties, one for each sql action: SelectCommand, InsertCommand, UpdateCommand, DeleteCommand.
Once an instance is created, each of the command property can be set.
The class also exposes a two arguments constructor SqlDataSource(String, String) where the second argument specifies the SELECT command text.
I use Sqlite v1.0.79 and vs2010 to create a simple winform application.
I have a customer table, and want to use the SQLiteDataAdapter to easily insert, update and delete records. So i do not need to type the whole insert, update and delete statements.
So i have a Customer class with a static load function that returns a dataset.
private static SQLiteDataAdapter _Adapter;
internal static DataSet Load(long id)
{
var q = "SELECT * FROM Customer WHERE id = {0}".FormatInvariant(id);
var cmd = new SQLiteCommand();
cmd.Connection = [_Connection];
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 10;
cmd.CommandText = commandText;
return cmd; _Adapter = new SQLiteDataAdapter();
_Adapter.SelectCommand = cmd;
var ds = new DataSet();
_Adapter.Fill(ds, "Customer");
if (id == 0)
{
ds.AddRow(ds.NewRow());
}
var b = new SQLiteCommandBuilder(_Adapter);
_Adapter.AcceptChangesDuringUpdate = true;
_Adapter.InsertCommand = b.GetInsertCommand();
_Adapter.UpdateCommand = b.GetUpdateCommand();
_Adapter.DeleteCommand = b.GetDeleteCommand();
// Commented out code for note A:
////ds.SetRowValue("lastname", "blaat44");
////_Adapter.Update(ds, "Customer");
return ds;
}
After calling the Load method, the DataSet is used in bindings on a windows form. And after some changes, the Save method is called, where the changes supposed to be saved.
internal static void Save(DataSet data)
{
//// data.AcceptChanges();
_Adapter.Update(data, "Customer");
}
But after the update, the database is not updating anything. What am i missing? I already tried the data.AcceptChanges before the update, but nothing works.
btw. the dataset in the save methods does have the 'right' values, but the update or insert is not working....
The strange thing is if i change a field in the dataset in the Load method (the commented out code at Note A in the example above), the data is saved correctly.
Im not an expert and have a basic understanding of sqlite etc but could the problem be that you are passing the dataset to the save function so the adapter is using a copy maybe of the original dataset. Which is why it works in the load method as the adapter is acessing tje original dataset?
Again this maybe complete babble and i may not understand but ive found sometimes the uneducated answer is a very good push in the right direction
I need some help with correctly implementing the USING statement with strongly typed TableAdapters
I have something like this:
Using myDT As New mbr_Account.mbr_AccountDataTable
Using myTA As New mbr_AccountTableAdapters.mbr_AccountTableAdapter
myTA.Connection.Open()
myTA.Fill(myDT)
myTA.Connection.Close()
End Using
For Each row In myDT
'do stuff
Next
End Using
This would correctly dispose of the datatable and tableadapter but does not address the issue of the connection object.
How should I dispose the Connection object?
I could wrap the connection in a Try... Finally like this:
Using myDT As New mbr_Account.mbr_AccountDataTable
Using myTA As New mbr_AccountTableAdapters.mbr_AccountTableAdapter
Try
myTA.Connection.Open()
myTA.Fill(myDT)
Finally
If Not IsNothing(myTA.Connection) Then
myTA.Connection.Close()
myTA.Connection.Dispose()
End If
End Try
End Using
For Each row In myDT
'do stuff
Next
End Using
Question : How can I use the USING keyword instead of Try.. Finally for the connection object?
Any reason you can't use a DataReader thus?
Dim sql As String = "SELECT whatever FROM SomeTable"
Using myConnection As New SqlConnection(MyConnectionstring)
Using myCommand As New SqlCommand(sql, myConnection)
myConnection.Open()
Using myReader As SqlDataReader = myCommand.ExecuteReader()
Dim myTable As New DataTable()
myTable.Load(myReader)
myConnection.Close()
Return myTable
End Using
End Using
End Using
The connection will be closed and disposed of automatically.
I have just found out that TableAdapters handle opening and closing of connections automatically and there is no need to manually add the code.
Basically, they already contain Try ... Finally blocks to handle closing of connections during exceptions.
The Designer generated Insert/Delete/Update code looks like this:
global::System.Data.ConnectionState previousConnectionState = this.Adapter.InsertCommand.Connection.State;
if (((this.Adapter.InsertCommand.Connection.State & global::System.Data.ConnectionState.Open)
!= global::System.Data.ConnectionState.Open)) {
this.Adapter.InsertCommand.Connection.Open();
}
try {
int returnValue = this.Adapter.InsertCommand.ExecuteNonQuery();
return returnValue;
}
finally {
if ((previousConnectionState == global::System.Data.ConnectionState.Closed)) {
this.Adapter.InsertCommand.Connection.Close();
}
}
Therefore no need to close or dispose the connection object.
I have a *.MDB database file, and I am wondering if it is possible or recommended to work against it using LINQ in C#. I am also wondering what some simple examples would look like.
I don't know a lot about LINQ, but my requirements for this task are pretty simple (I believe). The user will be passing me a file path to Microsoft Access MDB database and I would like to use LINQ to add rows to one of the tables within the database.
What you want is a LINQ to ODBC provider, or a LINQ to JET/OLEDB provider.
Out of the box, MS doesn't make one. There may be a 3rd party who does.
Actually I recently (today) discovered that you can access an Access database with LinqToSql. It must be in the 2002 or newer format, you will not be able to drag and drop the tables to your datacontext so either manually create the objects in your dbml or you can use SQL Server Migration for Access to move it to a sql server and then drag and drop all you want. When you want to actually create the context pass it an OleDbConnection. Use your standard Jet.OLEDB.4.0 connection string on the OleDbConnection and you are good to go. Not sure of the limitation this may incurr though. I just did a quick sample and did an OrderBy without issue.
I wrote a small sample program to test this out with David's answer. You'll need to make an access database and manually create the DBML for Linq-to-SQL, as you cannot drag 'n drop them.
Inserts fail, citing Missing semicolon (;) at end of SQL statement. but queries seem to work alright.
using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using Linq2Access.Data;
namespace Linq2Access
{
class Program
{
static readonly string AppPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
static readonly string DbPath = Path.Combine(AppPath, "Data", "database.accdb");
static readonly string DbConnString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + DbPath + "';Persist Security Info=False;";
static void Main(string[] args)
{
if (!File.Exists(DbPath))
throw new Exception("Database file does not exist!");
using (OleDbConnection connection = new OleDbConnection(DbConnString))
using (DataRepositoryDataContext db = new DataRepositoryDataContext(connection))
{
List<dbProject> projects = new List<dbProject>();
for (int i = 1; i <= 10; i++)
{
dbProject p = new dbProject() { Title = "Project #" + i };
for (int j = 1; j <= 10; j++)
{
dbTask t = new dbTask() { Title = "Task #" + (i * j) };
p.dbTasks.Add(t);
}
projects.Add(p);
}
try
{
//This will fail to submit
db.dbProjects.InsertAllOnSubmit(projects);
db.SubmitChanges();
Console.WriteLine("Write succeeded! {0} projects, {1} tasks inserted",
projects.Count,
projects.Sum(x => x.dbTasks.Count));
}
catch(Exception ex)
{
Console.WriteLine("Write FAILED. Details:");
Console.WriteLine(ex);
Console.WriteLine();
}
try
{
//However, if you create the items manually in Access they seem to query fine
var projectsFromDb = db.dbProjects.Where(x => x.Title.Contains("#1"))
.OrderBy(x => x.ProjectID)
.ToList();
Console.WriteLine("Query succeeded! {0} Projects, {1} Tasks",
projectsFromDb.Count,
projectsFromDb.Sum(x => x.dbTasks.Count));
}
catch (Exception ex)
{
Console.WriteLine("Query FAILED. Details:");
Console.WriteLine(ex);
Console.WriteLine();
}
Console.WriteLine();
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
}
You can use a DataSet. There are linq extensions that will allow you to query the data with all that LINQ goodness we have become use to :)
eICATDataSet.ICSWSbuDataTable tbl = new eICATDataSet.ICSWSbuDataTable();
ICSWSbuTableAdapter ta = new ICSWSbuTableAdapter();
ta.Fill(tbl);
var res = tbl.Select(x => x.ProcedureDate.Year == 2010);
I have seen this question a lot and in several fora. I made a go at it and here is a complete answer for those who have been looking at it.
LinQ was not made for Access. However, many of the queries will work with Access, including delete procedure. So, according to me, there are only 2 crucial deficiencies when working with Access, which are:
not being able to save data.
not being able to drag and drop objects onto the dbml
Insert will fail with the error "missing semicolon (;)". This is because LinQ save procedure was made to save data and retrieve the primary key ID of the record saved in one go. We know that you cannot execute multiple SQL statements in Access, so that is the reason for that failure.
Update will fail with the error "record not found". An update procedure will of cause look for the record to be updated then update it. I cannot tell why it wouldn't find it, when normal LinQ query to find a record works fine.
Because there is so much benefit to use LinQ, I figured out how to work around the deficiency, while enjoy the other benefits throughout my application. This is how (NB: My codes are in VB.net, but you can convert if required):
Create the LinQ to SQL (.dbml) class to manage your LinQ against the access database, and a way to manager your save procedure. Below is the full procedures of what I created and I now work with LinQ to Access without any problems:
Add a DataGridView on a form. Add buttons for Add, Edit & Delete
Code to fill the grid:
Private Sub ResetForm()
Try
Using db As New AccessDataClassesDataContext(ACCCon)
Dim rows = (From row In db.AccountTypes
Where row.AccountTypeID > 1
Order By row.AccountTypeID Ascending
Select row).ToList()
Me.DataGridView1.DataSource = rows
End Using
Catch ex As Exception
MessageBox.Show("Error: " & vbCr & ex.ToString, "Data Error", MessageBoxButtons.OK)
End Try
End Sub
DetailForm
Code to set control values
Private Sub ResetForm()
Try
If _accountTypeID = 0 Then
Exit Sub
End If
Using db As New AccessDataClassesDataContext(ACCCon)
'Dim rows = (From row In db.AccountTypes
' Where row.AccountTypeID = _accountTypeID
' Order By row.AccountTypeID Ascending
' Select row.AccountTypeID, row.AccountType, row.LastUpdated).ToList()
Dim rows = (From row In db.AccountTypes
Where row.AccountTypeID = _accountTypeID
Select row).ToList()
For Each s In rows
Me.AccountTypeIDTextBox.Text = s.AccountTypeID
Me.myGuidTextBox.Text = s.myGuid
Me.AccountTypeTextBox.Text = s.AccountType
Me.AcHeadIDTextBox.Text = s.AcHeadID
Me.DescriptionTextBox.Text = s.Description
Me.LastUpdatedDateTimePicker.Value = s.LastUpdated
Next
End Using
Catch ex As Exception
End Try
End Sub
LinQToSQLClass
You will have to add the data objects to the dbml manually since you cannot drag and drop when using Access. Also note that you will have to set all the properties of the fields correctly in the properties windows. Several properties are not set when you add the fields.
Code to Save
Public Function SaveAccountType(Optional ByVal type As String =
"Close") As Boolean
Dim success As Boolean = False
Dim row As New AccountType
Using db As New AccessDataClassesDataContext(ACCCon)
If _accountTypeID > 0 Then
row = (From r In db.AccountTypes
Where r.AccountTypeID = _accountTypeID).ToList()(0)
If String.IsNullOrEmpty(row.AccountTypeID) Then
MessageBox.Show("Requested record not found", "Update Customer Error")
Return success
End If
End If
Try
With row
.myGuid = Me.myGuidTextBox.Text
.AccountType = Me.AccountTypeTextBox.Text
.Description = Me.DescriptionTextBox.Text
.AcHeadID = Me.AcHeadIDTextBox.Text
.LastUpdated = Date.Parse(Date.Now())
End With
If _accountTypeID = 0 Then db.AccountTypes.InsertOnSubmit(row)
db.SubmitChanges()
success = True
Catch ex As Exception
MessageBox.Show("Error saving to Customer: " & vbCr & ex.ToString, "Save Data Error")
End Try
End Using
Return success
End Function
Now replace these two lines:
If _accountTypeID = 0 Then db.AccountTypes.InsertOnSubmit(row)
db.SubmitChanges()
with something like this:
Dim cmd As IDbCommand
cmd = Me.Connection.CreateCommand()
cmd.Transaction = Me.Transaction
cmd.CommandText = query
If myGuid.Trim.Length < 36 Then myGuid = UCase(System.Guid.NewGuid.ToString())
cmd.Parameters.Add(New OleDbParameter("myGuid", row.myGuid))
cmd.Parameters.Add(New OleDbParameter("AccountType", row.AccountType))
cmd.Parameters.Add(New OleDbParameter("Description", row.Description))
cmd.Parameters.Add(New OleDbParameter("AcHeadID", row.AcHeadID))
cmd.Parameters.Add(New OleDbParameter("LastUpdated", Date.Now))
If AccountTypeID > 0 Then cmd.Parameters.Add(New OleDbParameter("AccountTypeID", row.AccountTypeID))
If Connection.State = ConnectionState.Closed Then Connection.Open()
result = cmd.ExecuteNonQuery()
cmd = Me.Connection.CreateCommand()
cmd.Transaction = Me.Transaction
cmd.CommandText = "SELECT ##IDENTITY"
result = Convert.ToInt32(cmd.ExecuteScalar())
The last part of the code above is what gets you the ID of the record saved. Personally, I usually make that an option, because I don't need it in most of the cases, so I don't need to add that overhead of fetching back data every time a record is saved, I am happy just to know a record was saved.
That is the overhead added to LinQ, which causes Insert to fail with Access. Is it really necessary to have it? I don't think so.
You may have noted that I normally put my Update and Insert procedures together, so that saves me time and has address both the Insert & Update procedures in one go.
Code for Delete:
Private Sub DelButton_Click(sender As Object, e As EventArgs) Handles DelButton.Click
Using db As New AccessDataClassesDataContext(ACCCon)
Dim AccountTypeID As Integer = Me.DataGridView1.CurrentRow.Cells(0).Value
Dim row = From r In db.AccountTypes Where r.AccountTypeID = AccountTypeID
For Each detail In row
db.AccountTypes.DeleteOnSubmit(detail)
Next
Try
db.SubmitChanges()
Catch ex As Exception
' Provide for exceptions.
MsgBox(ex)
End Try
End Using
End Sub
Now you can enjoy LinQ to Access! Happy coding :)
LINQ to SQL only works for SQL Server databases. What you need is the Microsoft Entity Framework. This makes object oriented access to your mdb. From this you can run LINQ queries.
http://msdn.microsoft.com/en-us/library/aa697427(vs.80).aspx
I am using a codebehind page in ASP.NET to perform a SQL query. The query is loaded into a string, the connection is established (To Oracle), and we get it started by having the connection perform .ExecuteReader into a OleDBDataReader (We'll call it DataRead). I'll try to hammer out an example below. (Consider Drop as an ASP DropDownList control)
Dim LookFor as String = "Fuzzy Bunnies"
While DataRead.Read
If LookFor = DataRead.Item("Kinds of Bunnies") Then
'Meets special critera, do secondary function'
Drop.Items.Add(DataRead.Item("Subgroup of Bunnies"))
...
End if
...
End While
This is the only way I know of doing a dynamic add to a DropDownList. However, each item in a DropDownList has a .text property and a .value property. How can we define the .value as being different from the .text in code?
The Add function can take a ListItem, so you can do
Dim li as new ListItem(DataRead.Item("Subgroup of Bunnies"), "myValue")
Drop.Items.Add(li)
Add should have an overload that accepts a ListItem object. Using that, you can usually do something like this:
Drop.Items.Add(New ListItem("Text", "Value"))
If I understand the question, Items.Add has an overload that takes a ListItem, so you could create a new ListItem object in that line:
Drop.Items.Add(new ListItem("text", "value"))
Pardon my possibly faulty VB
Dim item as New ListItem()
item.Value = "foo"
item.Text = "bar"
Drop.Items.Add(item)
You can also use the ListItem constructor (e.g. new ListItem("text", "value"))
you'd select a second column into your datareader (such as an IDENTITY field) and then assign do your Item generation like this:
Dim item as new listitem
item.text = DataRead.Item("SubGroup Of Bunnies")
item.value = DataRead.Item("ID")
Drop.Items.Add(item)
You may also want to look into the DATABIND functionality, and filtering out "FUZZY BUNNIES" in the SQL statement itself.