The model in the parameter has values all the way to the DAL method where the query is but somehow nothing changes in the database. Anyone got any clue why? Also no errors occurred.
Controller:
public ActionResult AddCar(CarModel car)
{
if(ModelState.IsValid)
{
u.AddCar(new DTO.CarDTO(car.Color, car.Type, car.NumberOfSeats, car.Price, car.MaxKilometres, car.Addition, car.ModelID, car.License_Plate, car.Fueltype, car.ReservationStatus));
return RedirectToAction("Index", "Home");
}
return View();
}
Logic:
public void AddCar(CarDTO c)
{
carDAL.AddCar(new CarDTO(c.Color, c.Type, c.NumberOfSeats, c.Price, c.MaxKilometres, c.Addition, c.ModelID, c.License_Plate, c.Fueltype, c.ReservationStatus));
}
Interface layer:
public interface ICarDAL<CarDTO>
{
public void AddCar(CarDTO c) { }
}
DAL, class does have connectionstring:
public void AddCar(CarDTO c)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
string query = "INSERT INTO [dbo].[Car](Price, Addition, License_Plate, MaxKm, Type, Color, NumberOfSeats, Fueltype, reservationStatus, ModelID) " +
"VALUES(#Price, #Addition, '#LicensePlate', #MaxKm, '#Type', '#Color', #NumberOfSeats, #FuelType, #Reserved, #ModelID)";
using (SqlCommand cmd = new SqlCommand(query, con))
{
cmd.Parameters.AddWithValue("#Price", c.Price);
cmd.Parameters.AddWithValue("#Addition", c.Addition);
cmd.Parameters.AddWithValue("#LicensePlate", c.License_Plate);
cmd.Parameters.AddWithValue("#MaxKm", c.MaxKilometres);
cmd.Parameters.AddWithValue("#Type", c.Type);
cmd.Parameters.AddWithValue("#Color", c.Color);
cmd.Parameters.AddWithValue("#NumberOfSeats", c.NumberOfSeats);
cmd.Parameters.AddWithValue("#FuelType", c.Fueltype);
cmd.Parameters.AddWithValue("#ReservationStatus", c.ReservationStatus);
cmd.Parameters.AddWithValue("#ModelID", c.ModelID);
}
}
}
Found the error but I still dont know how to fix it:
https://imgur.com/xjKIqED
Solution: First of all I needed to use ExecuteNonQuery() to make the query actually do something...I thought SqlCommand already executed it for you. Secondly my password consisted out of ************ which I thought it wouldn't matter but I guess it did.
public void AddCar(CarDTO c)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
if (con.State==ConnectionState.Closed)
{
con.Open();
}
[Your code]
con.Close();
}
}
You may need to use a "save" function, I'm not seeing anywhere in your code where the SQL command is actually executed, I see it being built, but I've used it in the past with something similar like cmd.Execute()
Related
I have created a simplified SQL Data class, and a class method for returning a ready to use resultset:
public SQL_Data(string database) {
string ConnectionString = GetConnectionString(database);
cn = new SqlConnection(ConnectionString);
try {
cn.Open();
} catch (Exception e) {
Log.Write(e);
throw;
}
}
public SqlDataReader DBReader(string query) {
try {
using (SqlCommand cmd = new SqlCommand(query, this.cn)) {
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
} catch {
Log.Write("SQL Error with either Connection String:\n" + cn + " \nor Query:\n" + query);
throw;
}
}
(I catch any errors, log them, and then catch the error higher up the chain. Also, I did not include the ConnectionString() code for brevity. It just returns the requested connection string. That's all.)
This all works just fine, and with a single line of code, I'm ready to .Read() rows.
SqlDataReader rs = new SQL_Data("MyDatabase").DBReader(#"SELECT * FROM Employees");
while (rs.Read()) {
// code
}
rs.Close();
I want to expand this and add a .ColumnReader() method that I want to chain to .DBReader() like this:
string empID = new SQL_Data("MyDatabase").DBReader(#"SELECT * FROM Employees).ColumnReader("EmpID");
I attempted this by adding a .ColumnReader() method, but it ends up being a method of SQL_Data() class directly, not a member or extension of .DBReader(). I also tried adding the .ColumnReader() inside the .DBReader() (like a "closure"), but that didn't work either.
Can this be done?
This ended up working for me:
public static class SQLExtentions {
public static dynamic ColumnReader(this SqlDataReader rs, string colName) {
return rs[colName];
}
}
I will have to expand on it a bit to add some error checking, and perhaps return more than just the dynamic value - like return an object with the value and it's SQL data type. But Paul and Bagus' comments got me on the right track.
Hi I'm writing a program that IO from databses and I have the following function to read from the database and adds the rows to a combobox:
private void loadFromTuzel()
{
string constring = "Server=localhost;Database=ozturk;Uid=____;pwd=_____";
MySqlConnection newCon = new MySqlConnection(constring);
string selectCommand = "SELECT * FROM ozturk.tuzelkisi";
MySqlCommand cmd = new MySqlCommand(selectCommand, newCon);
MySqlDataReader myReader;
newCon.Open();
myReader = cmd.ExecuteReader();
while (myReader.Read())
{
cbselected.Items.Add(myReader["name"].ToString() + " " + myReader["Surname"].ToString());
}
}
as can be seen from the code the program loads the data from database to the combobox...
I need to use this function in a different form but need to load the data to a different combo box and I'm wondering if adding a toolbox item as a parameter to my function is possible so that it would be something like this
private void myfunction(thecombobox parameter comes here)
{
// The execution code and than
// thecomboboxparameter.items.add......
}
so I can use this function over and over at different forms just by adding the parameter value, is something like this possible?
Thanks
Yes, it is possible, but you'd be much better suited by moving that logic outside of your UI code altogether, and just return the items from the database. Don't pass the ComboBox to a parameter, but get the results from that method, and in your UI then tie everything together.
This is the basis of Separation of Concerns. Your ComboBoxes shouldn't care where the data comes from. They only care that they have data to display.
For the simple answer to your question, just adjust your method like this:
public static class Utilities
{
public static void loadFromTuzel(ComboBox cbo)
{
/// All of you other logic
while (myReader.Read())
{
cbo.Items.Add(myReader["name"].ToString() + " " +
myReader["Surname"].ToString());
}
}
}
If you follow SoC, then you'd have something like this:
public class Repository {
public IEnumerable<string> GetNamesFromTuzel()
{
// All of the same logic
while (myReader.Read())
{
yield return myReader["name"].ToString() + " " +
myReader["Surname"].ToString();
}
}
}
I'm trying to fetch data from DB with optional overload to pass the connection. I could do it in two ways.
public DataTable GetData()
{
using (SqlConnection con = new SqlConnection("..."))
{
return GetData(con);
}
}
public DataTable GetData(SqlConnection con)
{
// fetch data
return dtData;
}
or
public DataTable GetData(SqlConnection con=null)
{
bool OpenCon = false;
if (con == null)
{
con = new SqlConnection("...");
OpenCon = true;
}
try
{
// fetch data
}
finally
{
if (OpenCon)
con.Close();
}
return dtData;
}
The first case seems impressive. However, I am getting tons of methods for each transaction. In the second case, lots of code need to be written in each method as there is no way to use "using" block in this case.
The situation is still worse with other transactions like update or delete, since I need to have another overload to pass the transaction.
Is there a better way?
1st one is the best choice
public DataTable GetData()
{
using (SqlConnection con = new SqlConnection("..."))
{
return GetData(con);
}
}
public DataTable GetData(SqlConnection con)
{
// fetch data
return dtData;
}
Here you have Object oriented implementation, providing specific boundry as well as removal of object(using statement to destory objects ) are all there which is a good programmaing.
I have an insertion query in this function :
public string Insert_Piece(List<Piece> liste)
{
this.Connect();
using (connexion)
{
using (SqlCommand sqlCmd = new SqlCommand("INSERT INTO Piece (IDPiece, IDSuperlot, Url) VALUES (#idpiece, #idsuperlot, #url)", connexion))
{
foreach (Piece p in liste)
{
sqlCmd.Parameters.AddWithValue("#idpiece", p.Id_piece);
sqlCmd.Parameters.AddWithValue("#idsuperlot", p.Id_super_lot);
sqlCmd.Parameters.AddWithValue("#url", p.Url_piece);
try
{
sqlCmd.ExecuteNonQuery();
}
catch (Exception e) { return e.ToString(); }
}
return "cava";
}
}
}
But always an exception appears:
I don't know what is the problem and how can i fix it . The 3 attributs are string (varchar) and the selection queries works fine without problem.
What is the matter?
How can i fix it?
It looks like the issue is you are trying to insert too long of a string into the varchar column, try making the varchar column larger or changing it to be a text column.
I am confuse where can i make my code to n-tier:
While learning n-tier i know now how to insert,delete,update.
But now i am confused how to deal with sqldatareader to bind data on listbox and combo box:
This code works on my presentation layer but dont know how to convert it to layers as DataAccess,BusinessObject,BusinessLogic.
FormLoad
{
getlistview();
cboStatus();
}
#region "fill listview"
public void GetlistView()
{
int i = 0;
SqlConnection sqlcon = new SqlConnection(connStr);
lstBF.Items.Clear();
SqlCommand sqlcom = new SqlCommand("sp_LoadNew", sqlcon);
SqlDataReader dr;
lstBF.Items.Clear();
sqlcon.Open();
dr = sqlcom.ExecuteReader();
while (dr.Read())
{
lstBF.Items.Add(dr["SerialNumber"].ToString());
lstBF.Items[i].SubItems.Add(dr["PartNumber"].ToString());
lstBF.Items[i].SubItems.Add(dr["StatusDescription"].ToString());
lstBF.Items[i].SubItems.Add(dr["CustomerName"].ToString());
lstBF.Items[i].SubItems.Add(dr["DateCreated"].ToString());
lstBF.Items[i].SubItems.Add(dr["CreatedBy"].ToString());
lstBF.Items[i].SubItems.Add(dr["ModifiedBy"].ToString());
i = i + 1;
}
if (sqlcon.State == ConnectionState.Open) sqlcon.Close();
}
#endregion
#region "ListviewChange"
private void lstBF_SelectedIndexChanged(object sender, EventArgs e)
{
if (lstBF.SelectedItems.Count == 1)
{
txtSerialNumber.Text = lstBF.SelectedItems[0].Text;
txtPartNumber.Text = lstBF.SelectedItems[0].SubItems[1].Text;
lblStatus.Text = lstBF.SelectedItems[0].SubItems[2].Text;
lblcustomer.Text = lstBF.SelectedItems[0].SubItems[3].Text;
lblModifiedBy.Text = lstBF.SelectedItems[0].SubItems[6].Text;
}
}
#endregion
#region "FILL combo"
public void cboStatus()
{
try
{
SqlConnection conn = new SqlConnection(connStr);
SqlCommand sqlcom = new SqlCommand("sp_loadStatus",conn);
SqlDataReader dr = null;
conn.Open();
dr = sqlcom.ExecuteReader();
cmbStatus.Items.Clear();
while (dr.Read())
{
cmbStatus.Items.Add((dr["StatusDescription"]));
}
if (conn.State == ConnectionState.Open) conn.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error Occurred:" + ex);
}
finally
{
}
}
#endregion
If you want to have a nice, clean separation, here's what you should do:
never ever pass something like a SqlDataReader or any other database-dependant object up from your data layer - encapsulate everything in your data layer, and from there on up, use your own domain model (classes)
the data layer should turn your database requests into objects of your domain model. You can definitely do that by hand - but it's a lot of boring and error prone code to do all the DataReader, read each row, convert to object kind of stuff - here, a tool called an OR mapper (object-relational mapper) can help tremendously, since it does all of this for you - more or less for free. Check out SubSonic, Linq-to-SQL and quite a few more out there.
for things like combobox lookup lists, you would typically design a "view model", e.g. a class for that "view" (or webform, or winform) that will hold the data that this view is supposed to a) show, and b) needs for its job. Typically, such a "view model" is just another class - no magic about it. It will contain one or several of your domain model classes (the actual data you want to show), and one or several lookup lists that contain the possible values for all the dropdowns etc.
With this approach, you should be fine and well on track to a good solid design, and by using an ORM, you can save yourself a ton of boring code and concentrate on the more interesting parts of your app.
Update:
Sample for binding your combo box:
create a class for your lookup values, typically something like:
public class StatusCode
{
public int ID { get; set; }
public string Description { get; set; }
}
have a method in your data layer to retrieve all values from your StatusCode table into a List<StatusCode>
public List<StatusCode> GetAllStatusCodes();
have your combo box in the UI bound to that list:
cbxStatusCode.DataSource = statusCodeList;
cbxStatusCode.DisplayMember = "Description";
cbxStatusCode.ValueMember = "ID";
Note: this is slightly different depending on whether you use Winforms or ASP.NET webforms.
There you have it!
One place you could start is using the Entity Framework or a class generator like Subsonic.
watch this podcast, follow it through and have a look at the code it creates for you:
http://www.techscreencast.com/language/dotnet/subsonic-getting-started-webcast/227