Passing values between Windows form and a database - c#

I faced a problem while trying to build a Windows form solution for a college assignment, and hope somebody can point out my mistake.
The solution is about a mobile shop. I have two classes, Apple and Android forms. I need to read the data in the database table, categorize the entries to either Android or Apple phones, and then display all phones in a list when the form loads.
I can successfully categorize phones, but when trying to read the entries, I always end up with the same entry twice in my list on the form, while the second entry doesn't appear at all.
I know I made a big stupid mistake while doing the connection but I can't find it!.
Here is my code:
public abstract class MobilePhone {
private Int32 phoneID;
private string operatingSystem;
private string make;
private string model;
public enum Condition { Poor, Fair, Good, Mint };
private Condition condition;
private decimal originalPrice;
private DateTime datePurchase;
private string description;
private clsDataConnection dbConnection;
//constructor
public MobilePhone(string make, string model, decimal originalPrice, DateTime datePurchase, Condition condition, string description) {
this.make = make;
this.model = model;
this.originalPrice = originalPrice;
this.datePurchase = datePurchase;
this.condition = condition;
this.description = description;
}
Not complete, but that's what is relevant:
public class ApplePhone : MobilePhone {
decimal ApproxValue;
public ApplePhone(string make, string model, decimal originalPrice, DateTime datePurchase, Condition condition, string description)
: base(make, model, originalPrice, datePurchase, condition, description) {
}
The Android class is the same but with different other functions.
class Shop {
clsDataConnection dbConnection;
const int NotAdded = -1; // invalid primary key
private string name;
private decimal ApproxValue;
private Int32 phoneID;
private string operatingSystem;
private string make;
private string model;
private MobilePhone.Condition condition;
private decimal originalPrice;
private DateTime datePurchase;
private string description;
Int32 Index;
private List<MobilePhone> phonesForSale;
//constructor
public Shop(string name) {
this.name = name;
}
MobilePhone phone;
public void SelectAll() {
dbConnection = new clsDataConnection();
dbConnection.Execute("SellectAllPhones");
}
public void FilterByOperatingSystem(string operatingSystem) {
dbConnection = new clsDataConnection();
dbConnection.AddParameter("#OperatingSystem", operatingSystem);
dbConnection.Execute("FilterByOperatingSystem");
}
public Int32 Count {
get {
//return the count of records
return dbConnection.Count;
}
}
public string DescribeCurrentPhone(int Index) {
Int32 phoneID;
string make;
string model;
MobilePhone.Condition condition;
decimal originalPrice;
DateTime datePurchase;
string description;
phoneID = Convert.ToInt32(phonesForSale[Index].PhoneID);
make = Convert.ToString(phonesForSale[Index].Make);
model = Convert.ToString(phonesForSale[Index].Model);
condition = phonesForSale[Index].GetCondition;
originalPrice = Convert.ToDecimal(phonesForSale[Index].OriginalPrice);
datePurchase = Convert.ToDateTime(phonesForSale[Index].DatePurchased);
description = Convert.ToString(phonesForSale[Index].Description);
//set up a new object of class list item
string listItemText = make + " " + "|" + " " + model + " " + "|" + " " + condition + " " + "|" + " " + "£" + Math.Round(originalPrice, 2) + " " + "|" + " " + datePurchase.ToShortDateString() + " " + "|" + " " + description;
return listItemText;
}
public List<MobilePhone> Allphones {
get {
phonesForSale = new List<MobilePhone>();
int count = Count;
Index = 0;
while (Index < count) {
phoneID = Convert.ToInt32(dbConnection.DataTable.Rows[Index]["PhoneId"]);
operatingSystem = Convert.ToString(dbConnection.DataTable.Rows[Index]["OperatingSystem"]);
make = Convert.ToString(dbConnection.DataTable.Rows[Index]["Make"]);
model = Convert.ToString(dbConnection.DataTable.Rows[Index]["Model"]);
string conditionString = Convert.ToString(dbConnection.DataTable.Rows[Index]["Condition"]);
originalPrice = Convert.ToInt32(dbConnection.DataTable.Rows[Index]["OriginalPrice"]);
datePurchase = Convert.ToDateTime(dbConnection.DataTable.Rows[Index]["DatePurchased"]);
description = Convert.ToString(dbConnection.DataTable.Rows[Index]["Description"]);
// Set Condition
if (conditionString == "Poor") {
condition = MobilePhone.Condition.Poor;
} else if (conditionString == "Fair") {
condition = MobilePhone.Condition.Fair;
} else if (conditionString == "Good") {
condition = MobilePhone.Condition.Good;
} else if (conditionString == "Mint") {
condition = MobilePhone.Condition.Mint;
}
//check Operating System
if (operatingSystem == "IOS") {
phone = new ApplePhone(make, model, originalPrice, datePurchase, condition, description);
//ApproxValue = ApplePhone.CalculateApproximateValue();
} else if (operatingSystem == "Android") {
phone = new AndroidPhone(make, model, originalPrice, datePurchase, condition, description);
//ApproxValue = AndroidPhone.CalculateApproximateValue();
}
Index++;
phonesForSale.Add(phone);
}
return phonesForSale;
}
}
And the form code is:
public partial class FormMain : Form {
public FormMain() {
InitializeComponent();
Shop shop = new Shop("");
}
private void FormMain_Load(object sender, EventArgs e) {
DisplayItems("");
}
protected int DisplayItems(string operatingSystem) {
Shop MyShop = new Shop("");
Int32 RecordCount;
Int32 Index = 0;
Int32 PID;
if (operatingSystem != "") {
MyShop.FilterByOperatingSystem(operatingSystem);
} else {
MyShop.SelectAll();
}
RecordCount = MyShop.Count;
ArrayList MyPhones = new ArrayList();
while (Index < RecordCount) {
// I Suspect this line is the problem but don't know how to fix it
PID = MyShop.Allphones[Index].PhoneID
string listItemText = MyShop.DescribeCurrentPhone(PID);
//add the new item to the list
MyPhones.Add(listItemText);
//increment the index
Index++;
}
listBox1.DataSource = MyPhones;
return RecordCount;
}
I am not used to connecting to databases, so any advice will be of help!

An example of an alternative to the DB connection you have made is below
List<MyPhone> myIPhoneList = new List<Myphone>();
List<MyPhone> myAndroidList = new List<Myphone>();
SqlConnection myDBConnection = new SqlConnection("MyConnectionString"); //DB Connection
SqlCommand dbCommand = new SqlCommand("SelectAllPhones"); //Stored Procedure
SqlDataReader recordReader = dbCommand.ExecuteReader(); //Execute
//Read records return in to phone objects
while (recordReader.Read()) {
var phoneField1 = recordReader["PhoneField1FromDatabase"];
var phoneField2 = recordReader["PhoneField2FromDatabase"];
//etc...
var myPhone = new MyPhone();
myPhone.Name = phoneField1;
//etc...
if (myPhone.OS == "iPhone")
myIPhoneList.Add(myPhone);
if (myPhone.OS = "Android")
myAndroidList.Add(myPhone);
}

Just a twist to Wheels answer really,
I'd personally put a filter on the stored-proc.
SqlCommand dbCommand = new SqlCommand("SelectAllPhones"); //Stored Procedure
becomes something like:
using (SqlConnection conn = new SqlConnection())
{
using (SqlCommand cmd = new SqlCommand("SelectAllPhones", conn))
{
cmd.Parameters.Add(new SqlParameter() { ParameterName = "#OS", SqlDbType = SqlDbType.VarChar, Direction = ParameterDirection.Input, Value = phoneOS });
cmd.CommandType = CommandType.StoredProcedure;
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
// load your data...
}
}
}
Only because there is very little point dragging both sets of phone data (android/iphone) for each class. You may as well only pull back the data you require.
Of course the Stored-Proc will need an update to cater for the parameter.
something like:
AND PhoneOS = #OS
needs appending to your SQL condition.
clsDataConnection dbConnection; is unknown to me - is this a third party library or a class you've wrote and not included?
public Int32 Count
{
get
{
//return the count of records
return dbConnection.Count;
}
}
dbConnection.Count seems very non-standard. Doesn't read as if you're trying to get the number of rows, more the number of connections - which is invalid here.
dbConnection.DataTables[0].Rows.Count; would be a better way of determining the rows using your existing code, as currently it reads as if your counting the number of database connections which isn't what your after - and would be redundant if using either mine or Wheels as you wont need to know beforehand how many rows your about to process.

Related

CS0266 - Cannot implicitly convert type "System IList" to "System ArrayList" - Software Testing

I am trying to create a couple of mock unit tests for my software test assignment and my GUI.cs file has an error that says it cannot implicitly convert type "System.Collections.IList" to "System.Collection.ArrayList"
this.accounts = database.GetAccounts();
However that file was untouched. By that I mean I didn't modify it. The only files I have modified are the unit test, the file database and the Idatabase, listed below, by changing some variable types such as renaming all my ArrayList to IList.
But my GUI has the error and I'm not able to figure out which file is the cause of it and which line of code.
Below is the GUI.cs file
The error is the "this.accounts..." line.
The two "dataGridView1" lines has some System.NullReferenceException error when I hover my mouse over it on Visual Studio. Could that be related to the error I'm having, I'm not so sure.
private void InitBankRead()
{
try
{
//database = new FileDatabase();
database = IoC.GetInstance().Resolve<IDatabase>();
this.accounts = database.GetAccounts();
this.dataGridView1.DataSource = accounts;
dataGridView1.Columns["Balance"].DefaultCellStyle.Format = "C";
foreach (DataGridViewColumn column in dataGridView1.Columns)
{
dataGridView1.Columns[column.Name].SortMode = DataGridViewColumnSortMode.Automatic;
}
}
=====================================================
=====================================================
EDIT:
Further down below are the rest of my files for anyone who wants to dig into it deeper. It's optional but it's there. My attempt is not to overwhelm you guys with the works I have, but to make sure you understand what I'm talking about.
IDatabase.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using Banking;
namespace Banking
{
public interface IDatabase
{
//IList<Account> FindAll();
//Account FindByAccount(int accountId);
//Account FindByName(int firstName, int lastName);
//bool Save(Account target);
bool AddNewCustomer(int customerId, string firstName, string lastName, decimal openingDeposit, Account.ACCOUNTTYPE type);
bool UpdateExistingAccount(char transactionType, Account account, decimal amount);
IList GetAccounts();
}
}
FileDatabase.cs
using System;
using System.Collections;
using System.IO;
using Banking;
namespace Banking
{
public class FileDatabase : IDatabase
{
private string filename;
private StreamWriter outFile;
private StreamReader inFile;
public const string DELIMETER = ",";
public FileDatabase()
{
this.filename = #"..\..\..\Banking\Data\Database.txt";
}
public bool AddNewCustomer(int customerID, string firstName, string lastName, decimal openingDeposit, Account.ACCOUNTTYPE type)
{
int accountID = GetAccounts().Count + 1;
using (outFile = File.AppendText(filename))
{
string output = accountID + DELIMETER + customerID + DELIMETER + firstName + DELIMETER + lastName + DELIMETER + openingDeposit + DELIMETER + Convert.ToInt32(type);
outFile.WriteLine(output);
outFile.Close();
}
return true;
}
public bool UpdateExistingAccount(char transactionType, Account account, decimal amount)
{
bool success = false;
try
{
switch (transactionType)
{
case 'D':
//account.Balance += amount;
account.deposit(amount);
break;
case 'W':
//account.Balance -= amount;
account.withdrawl(amount);
break;
}
IList accounts = GetAccounts();
int accountID = account.AccountID;
// Find and replace the account
for (int i = 0; i < accounts.Count; ++i)
{
if (accountID == ((Account) accounts[i]).AccountID)
{
accounts[i] = account;
}
}
using (outFile = new StreamWriter(filename))
{
foreach (Account acct in accounts)
{
outFile.WriteLine(acct.AccountID + DELIMETER + acct.Customer.CustomerID + DELIMETER + acct.Customer.FirstName + DELIMETER + acct.Customer.LastName + DELIMETER + acct.Balance + DELIMETER + Convert.ToInt32(acct.AccountType));
}
outFile.Close();
}
success = true;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
success = false;
}
return success;
}
public IList GetAccounts()
{
IList accounts = new ArrayList();
using (inFile = new StreamReader(filename))
{
int customerID;
int accountID;
string firstName;
string lastName;
decimal balance;
int accountType;
string line = string.Empty;
while ((line = inFile.ReadLine()) != null)
{
string [] data = line.Split(DELIMETER.ToCharArray()[0]);
customerID = Convert.ToInt32(data[0]);
accountID = Convert.ToInt32(data[1]);
firstName = Convert.ToString(data[2]);
lastName = Convert.ToString(data[3]);
balance = Convert.ToDecimal(data[4]);
accountType = Convert.ToInt32(data[5]);
Customer customer = new Customer(customerID, firstName, lastName);
Account account;
Account.ACCOUNTTYPE type = (Account.ACCOUNTTYPE) accountType;
if (type == Account.ACCOUNTTYPE.CHECKING)
{
account = new Checking(customer, accountID, Convert.ToDecimal(balance));
}
else
{
account = new Savings(customer, accountID, Convert.ToDecimal(balance));
}
accounts.Add(account);
}
inFile.Close();
}
return accounts;
}
}
}
UnitTest.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Banking;
using Moq;
namespace UnitTestsWithMoQ
{
[TestClass]
public partial class UnitTest1
{
public TestContext TestContext { get; set; }
public readonly IDatabase MockDatabase;
private IList accounts = new List<Account>
{
new Checking( new Customer(1, "Alex", "Parrish"), 12, 30.00M ),
new Savings( new Customer(2, "Alex", "Russo"), 12, 29.00M ),
new Checking( new Customer(3, "Emma", "Swan"), 12, 30.00M ),
new Savings( new Customer(4, "Henry", "Mills"), 12, 30.00M )
};
Mock<IDatabase> dataMock = new Mock<IDatabase>();
private string filename;
private StreamWriter outFile;
private StreamReader inFile;
public const string DELIMETER = ",";
public UnitTest1()
{
// Return all accounts
dataMock.Setup(repository => repository.GetAccounts()).Returns(accounts);
dataMock.Setup(repository => repository.UpdateExistingAccount(It.IsAny<char>(), It.IsAny<Account>(),
It.IsAny<decimal>())).Returns((char transactionType, Account account, decimal amountDecimal) =>
{
bool success = false;
try
{
switch (transactionType)
{
case 'D':
//account.Balance += amount;
account.deposit(amountDecimal);
break;
case 'W':
//account.Balance -= amount;
account.withdrawl(amountDecimal);
break;
}
var accounts = MockDatabase.GetAccounts();
int accountID = account.AccountID;
// Find and replace the account
for (int i = 0; i < accounts.Count; ++i)
{
if (accountID == ((Account) accounts[i]).AccountID)
{
accounts[i] = account;
}
}
// Find and replace the account
for (int i = 0; i < accounts.Count; ++i)
{
MockDatabase.GetAccounts()[i] = accounts[i];
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
success = false;
}
return success;
});
dataMock.Setup(repository => repository.AddNewCustomer(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<decimal>(),
It.IsAny<Account.ACCOUNTTYPE>())).Returns((int customerID, string firstName, string lastName, decimal openingDeposit, Account.ACCOUNTTYPE type) =>
{
int accountID = MockDatabase.GetAccounts().Count + 1;
using (outFile = File.AppendText(filename))
{
string output = accountID + DELIMETER + customerID + DELIMETER + firstName + DELIMETER + lastName + DELIMETER + openingDeposit + DELIMETER + Convert.ToInt32(type);
outFile.WriteLine(output);
outFile.Close();
}
return true;
});
MockDatabase = dataMock.Object;
}
}
}
If the error says cannot implicitly convert type "System.Collections.IList" to "System.Collection.ArrayList", you are then probably assigning an IList variable to an ArrayList variable.
Note that IList is an interface which is more generic than the concrete type ArrayList, so the compiler does not know how to convert it implicitly.
this.accounts = database.GetAccounts();
How is that accounts defined?
If it's defined as: ArrayList accounts then you will not be able to make that assignment.
Try changing it to: IList accounts

IsPostBack Issue

I am trying to do a 3 tier volunteers sign up for packaging session system. First, on the page load, I get the details of certain packaging session:
if (!IsPostBack)
{
string packingID = Request.QueryString["id"];
packingIndv = packing.getPacking(packingID);
if (packingIndv == null)
{
lbl_msg.Text = "Error in getting packing session details!";
}
else
{
lbl_ID.Text = packingIndv.packingID;
lbl_date.Text = packingIndv.date.ToString("dd/M/yyyy", CultureInfo.InvariantCulture); ;
lbl_location.Text = packingIndv.location;
lbl_volunteerAvailable.Text = packingIndv.volunteerAvailable.ToString();
lbl_status.Text = packingIndv.status;
}
}
After that, volunteers can click on the join button, and the program will execute:
In presentation layer after join button is on click:
string userLogged = Session["userLogged"].ToString();
UserBLL user = new UserBLL();
string userID = user.getUserIDByName(userLogged);
PackingBLL packing = new PackingBLL();
string msg = "";
msg = packing.joinPacking(userID, lbl_ID.Text);
lbl_msg.Text = msg;
In business logic layer:
public string joinPacking(string userID, string packingID)
{
string returnMessage = "";
if(returnMessage.Length == 0)
{
Packing packing = new Packing(userID, packingID);
Boolean success = packing.checkJoinedSession();
if (success)
{
returnMessage += "Same volunteer cannot join same packing session for more than once! <br/>";
}
else
{
int nofRows = 0;
nofRows = packing.joinPacking();
if (nofRows > 0)
{
returnMessage = "Request to volunteer for packing session saved successfully.";
int successUpdate = packing.updateRemaining();
if (successUpdate > 0)
{
getPacking(packingID);
}
}
else
{
returnMessage = "Error! Please try again.";
}
}
}
return returnMessage;
}
In data access layer:
public int updateRemaining()
{
int result = 0;
using (var connection = new SqlConnection(FFTHDb.connectionString)) // get your connection string from the other class here
{
SqlCommand command = new SqlCommand("UPDATE PackingSession SET volunteerAvailable = volunteerAvailable + 1 WHERE packingID = '" + packingID + "'", connection);
connection.Open();
result = command.ExecuteNonQuery();
connection.Close();
}
return result;
}
For every join from each volunteer, the volunteer available will be increased by one. What I am trying to do is from the page load, I display the details of packaging session. Then when volunteer joins it, the volunteerAvailable will straight away increased by one. All my database works perfectly, it just wont increase the volunteer available automatically after each successful update sql statement, as in I have to refresh the browser in order to see the changes.

Issues with INSERT statement (I think)

I'm working on a quote manager for my boss at work and I'm having some issues. This is a WPF C# application and it's the first time I've ever built anything that works with a SQL Server database. I'm currently having three issues.
Background:
When the user opens the application they're greeted with a DataGrid, a new quote button and several other controls that I haven't yet created. When they press the new quote button a new window pops up with a form that will have text boxes for things like Customer Name, quantity, etc. At the bottom of that form is a submit button, at which point the window will close and the information they added will be inserted into the DataGrid as a new row.
Problem One:
One of the fields in my database is called Open_Quote and it is supposed to be hold the date we received the order. This is handled programmatically and is what my first question involves. I'll include all of the code at the bottom of this post, but when the user hits submit I receive the following error: "Conversion failed when converting date and/or time from character string."
Problem Two:
In an attempt to test the rest of my code and go back later to fix the date issue, I commented that code out and tried running my program again. This time I get a different error: "Incorrect syntax around 'newQuote.Qty'."
Problem Three:
Again, commenting that code out in order to finally test the rest of my code, I received a third error: "string or binary data would be truncated. This process has been terminated."
My hope is that there's one piece of code that's causing all three of these issues, but I could be completely off there. I've been pulling my hair out for over a day trying to figure this out. Anyway, here's the code:
newQuote.xaml.cs:
private void SubmitQuotebtn_Click(object sender, RoutedEventArgs e)
{
CustomerData newQuote = new CustomerData();
int quantity;
quantity = Convert.ToInt32(Qtytxt.Text);
string theDate = System.DateTime.Today.Date.ToString("d");
newQuote.OpenQuote = theDate;
newQuote.CustomerName = CustNametxt.Text;
newQuote.OEMName = OemNametxt.Text;
newQuote.Qty = quantity;
newQuote.QuoteNumber = QuoteNumtxt.Text;
newQuote.FdNumber = FabDrawingNumtxt.Text;
newQuote.RfqNumber = RfqNumtxt.Text;
newQuote.RevNumber = RevNumtxt.Text;
try
{
string insertConString = Sqtm.Properties.Settings.Default.SqtmDbConnectionString;
using (SqlConnection insertConnection = new SqlConnection(insertConString))
{
insertConnection.Open();
SqlCommand cmd = new SqlCommand("INSERT INTO General_Info(Open_Quote, Customer_Name, OEM_Name, Qty, Quote_Num, Fab_Drawing_Num, "
+ "Rfq_Num, Rev_Num) values('newQuote.OpenQuote', 'newQuote.CustomerName', 'newQuote.OemName', 'newQuote.Qty' "
+ "'newQuote.QuoteNumber', 'newQuote.FdNumber', 'newQuote.RfqNumber', 'newQuote.RevNumber')", insertConnection);
cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
CustomerData.cs:
class CustomerData
{
private string _CustomerName;
private string _OEMName;
private string _OpenQuote;
private int _Qty;
private string _QuoteNumber;
private string _FdNumber;
private string _RfqNumber;
private string _RevNumber;
public CustomerData()
{
// empty constructor
}
public string CustomerName
{
get { return _CustomerName; }
set { _CustomerName = value; }
}
public string OpenQuote
{
get { return _OpenQuote; }
set { _OpenQuote = value; }
}
public string OEMName
{
get { return _OEMName; }
set { _OEMName = value; }
}
public int Qty
{
get { return _Qty; }
set { _Qty = value; }
}
public string QuoteNumber
{
get { return _QuoteNumber; }
set { _QuoteNumber = value; }
}
public string FdNumber
{
get { return _FdNumber; }
set { _FdNumber = value; }
}
public string RfqNumber
{
get { return _RfqNumber; }
set { _RfqNumber = value; }
}
public string RevNumber
{
get { return _RevNumber; }
set { _RevNumber = value; }
}
}
And as a reference, here's how I set up this table in SQLServer:
Open_Quote, date, not null
Customer_Name, varchar(25), not null
OEM_Name, varchar(25), null
Qty, int, not null
Qute_Num, varchar(20), null
Fab_Drawing_Num, varchar(20), not null
Rfq_Num, varchar(10), null
Rev_Num, varchar(10), null
Thanks in advance to anyone who helps me out,
Andrew
Try again with parameters and let us know how it goes.
http://www.dotnetperls.com/sqlparameter
Edit: Or what Tieson T. said. That'd be even better just a little more involved.
To get the data to show in the datagrid, after you do the insert, you can rebind the grid. Make sure your update the datasource so it repulls the data you just inserted. If you have problems, show where/how you are setting the datasource for the grid.
Try this:
SqlCommand cmd = new SqlCommand("INSERT INTO General_Info(Open_Quote, Customer_Name, OEM_Name, Qty, Quote_Num, Fab_Drawing_Num, "
+ "Rfq_Num, Rev_Num) values('" + newQuote.OpenQuote + "','" + newQuote.CustomerName + "','" + newQuote.OemName + "','" + newQuote.Qty + "','" + newQuote.QuoteNumber + "','" + newQuote.FdNumber + "', '" + newQuote.RfqNumber + "','" + newQuote.RevNumber + "' "
+ " )", insertConnection);

Using an ObjectDataSource with a GridView in a dynamic scenario

I have a search page that is tasked with searching 3.5 million records for individuals based on their name, customer ID, address, etc. The queries range from complex to simple.
Currently, this code relies on a SqlDataSource and a GridView. When a user types a serach term in and presses enter, the TextBoxChanged even runs a Search(term, type) function that changes the query that the SqlDataSource uses, adds the parameters, and rebinds the GridView.
It works well, but I've become obsessed with rewriting the code more efficiently. I want the paging to be done by SQL Server instead of the inefficiencies of a SqlDataSource in DataSet mode.
Enter the ObjectDataSource. Caveat: I have never used one before today.
I have spent the better part of the day putting together this class:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
/// <summary>
/// Summary description for MultiSearchData
/// </summary>
public class MultiSearchData
{
private string _connectionString = string.Empty;
private string _sortColumns = string.Empty;
private string _selectQuery = string.Empty;
private int _lastUpdate;
private int _lastRowCountUpdate;
private int _lastRowCount;
private SqlParameterCollection _sqlParams;
public MultiSearchData()
{
}
private void UpdateDate()
{
_lastUpdate = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
}
private string ReplaceFirst(string text, string search, string replace)
{
int pos = text.IndexOf(search);
if (pos < 0)
{
return text;
}
return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
}
public string SortColumns
{
get { return _sortColumns; }
set { _sortColumns = value; }
}
public SqlParameterCollection SqlParams
{
get { return _sqlParams; }
set { _sqlParams = value; }
}
public string ConnectionString
{
get { return _connectionString; }
set { _connectionString = value; }
}
public string SelectQuery
{
get { return _selectQuery; }
set
{
if (value != _selectQuery)
{
_selectQuery = value;
UpdateDate();
}
}
}
public DataTable GetFullDataTable()
{
return GetDataTable(AssembleSelectSql());
}
public DataTable GetPagedDataTable(int startRow, int pageSize, string sortColumns)
{
if (sortColumns.Length > 0)
_sortColumns = sortColumns;
return GetDataTable(AssemblePagedSelectSql(startRow, pageSize));
}
public int GetRowCount()
{
if (_lastRowCountUpdate == _lastUpdate)
{
return _lastRowCount;
}
else
{
string strCountQuery = _selectQuery.Remove(7, _selectQuery.IndexOf("FROM") - 7);
strCountQuery = strCountQuery.Replace("SELECT FROM", "SELECT COUNT(*) FROM");
using (SqlConnection conn = new SqlConnection(_connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(strCountQuery, conn))
{
if (_sqlParams.Count > 0)
{
foreach (SqlParameter param in _sqlParams)
{
cmd.Parameters.Add(param);
}
}
_lastRowCountUpdate = _lastUpdate;
_lastRowCount = (int)cmd.ExecuteScalar();
return _lastRowCount;
}
}
}
}
public DataTable GetDataTable(string sql)
{
DataTable dt = new DataTable();
using (SqlConnection conn = new SqlConnection(_connectionString))
{
using (SqlCommand GetCommand = new SqlCommand(sql, conn))
{
conn.Open();
if (_sqlParams.Count > 0)
{
foreach (SqlParameter param in _sqlParams)
{
GetCommand.Parameters.Add(param);
}
}
using (SqlDataReader dr = GetCommand.ExecuteReader())
{
dt.Load(dr);
conn.Close();
return dt;
}
}
}
}
private string AssembleSelectSql()
{
StringBuilder sql = new StringBuilder();
sql.Append(_selectQuery);
return sql.ToString();
}
private string AssemblePagedSelectSql(int startRow, int pageSize)
{
StringBuilder sql = new StringBuilder();
string originalQuery = ReplaceFirst(_selectQuery, "FROM", ", ROW_NUMBER() OVER (ORDER BY " + _sortColumns + ") AS ResultSetRowNumber FROM");
sql.Append("SELECT * FROM (");
sql.Append(originalQuery);
sql.Append(") AS PagedResults");
sql.AppendFormat(" WHERE ResultSetRowNumber > {0} AND ResultSetRowNumber <= {1}", startRow.ToString(), (startRow + pageSize).ToString());
return sql.ToString();
}
}
I don't know if it's pretty. It works. I give it a query in the ObjectCreating method:
protected void dataMultiSearchData_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
MultiSearchData info;
info = Cache["MultiSearchDataObject"] as MultiSearchData;
if (null == info)
{
info = new MultiSearchData();
}
info.SortColumns = "filteredcontact.fullname";
info.ConnectionString = "Data Source=SERVER;Initial Catalog=TheDatabase;Integrated Security=sspi;Connection Timeout=60";
info.SelectQuery = #"SELECT filteredcontact.contactid,
filteredcontact.new_libertyid,
filteredcontact.fullname,
'' AS line1,
filteredcontact.emailaddress1,
filteredcontact.telephone1,
filteredcontact.birthdateutc AS birthdate,
filteredcontact.gendercodename
FROM filteredcontact
WHERE fullname LIKE 'Griffin%' AND filteredcontact.statecode = 0";
e.ObjectInstance = info;
}
protected void dataMultiSearchData_ObjectDisposing(object sender, ObjectDataSourceDisposingEventArgs e)
{
MultiSearchData info = e.ObjectInstance as MultiSearchData;
MultiSearchData temp = Cache["MultiSearchDataObject"] as MultiSearchData;
if (null == temp)
{
Cache.Insert("MultiSearchDataObject", info);
}
e.Cancel = true;
}
Once the class has the query, it wraps it in paging friendly SQL and we're off to the races. I've implemented caching so that it can skip some expensive queries. Etc.
My problem is, this completely breaks my pretty little Search(term, type) world. Having ot set the query in the ObjectCreating method is completely harshing my vibe.
I've been trying to think of a better way to do this all day, but I keep ending up with a really messy...do it all in ObjectCreating model that just turns my stomach.
How would you do this? How can I keep the efficiency of this new method whilst have the organizational simplicity of my former model?
Am I being too OCD?
I determined that it can't be done. Furthermore, after benchmarking this class I found it performed no better than a SqlDataSource but was much more difficult to maintain.
Thus I abandoned this project. I hope someone finds this code useful at some point though.

How to increment the string value during run time without using dr.read() and store it in the oledb db?

Here is my code, everything is working fine the only problem is with the ReadData() method in which i want the string value to be increment i.e AM0001,AM0002,AM0003 etc. This is happening till the execution of the program once i stop the execution of program, the second time when i run the program the same value i.e AM0001 is getting return. Due to this i am getting a error from oledb because of AM0001 is a primary key field.
This is my code:
class Jewellery : Connectionstr
{
string lmcode;
public string LM_code
{
get { return lmcode;}
set { lmcode = ReadData();}
}
string mname;
public string M_Name
{
get { return mname; }
set { mname = value;}
}
string desc;
public string Desc
{
get { return desc; }
set { desc = value; }
}
public string ReadData()
{
string jid = string.Empty;
string displayString = string.Empty;
String query = "select max(LM_code)from Master_Accounts";
Datamanager.RunExecuteReader(Constr,query);
jid = LM_code;// this is working on first execution, the second time when i run the program the value null defined in LM_code.
if (string.IsNullOrEmpty(jid))
{
jid = "AM0000";//This string value has to increment at every time, but it is getting increment only one time.
}
int len = jid.Length;
string split = jid.Substring(2, len - 2);
int num = Convert.ToInt32(split);
num++;
displayString = jid.Substring(0, 2) + num.ToString("0000");
return displayString;
}
public void add()
{
String query ="insert into Master_Accounts values ('" + LM_code + "','" + M_Name + "','" + Desc + "')";
Datamanager.RunExecuteNonQuery(Constr , query);
}
Any help will be appreciated.
Do not declare jid in method, declare it in class level:
private string jid = string.Empty;

Categories

Resources