I threw together a small solution for my organization today for some basic data review and approval procedures. This particular application will likely not change or add functionality at any time.
My question as I was coding the application was, does this need to be decoupled? Are there any opportunities for a Factory Pattern or Dependency Injection? Is following those patterns just adding too much to a program that doesn't really need it? (YAGNI?)
I kept coming to the conclusion that adding any of the above would be overkill, but I am a Lone Ranger developer at my company so I thought I would get the opinion of the community at large.
The application consists of two domain level classes and a Form
.
MAIN FORM
using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace StockoutReasonReview
{
public partial class StockoutReasonReviewForm : Form
{
private ReasonData ReasonData { get; set; }
public StockoutReasonReviewForm()
{
InitializeComponent();
this.ReasonData = new ReasonData();
SetupDgv();
}
private void CloseButton_Click(object sender, EventArgs e)
{
this.ReasonData.ReasonTable.Dispose();
this.Close();
}
private void SubmitButton_Click(object sender, EventArgs e)
{
this.ReasonData.Submit();
}
private void SetupDgv()
{
dgvReasons.DataSource = this.ReasonData.ReasonTable;
dgvReasons.DefaultCellStyle.BackColor = Color.LightBlue;
dgvReasons.AlternatingRowsDefaultCellStyle.BackColor = Color.LightCyan;
dgvReasons.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
var approvedColumn = new DataGridViewCheckBoxColumn
{
Name = "approved_check",
DataPropertyName = "approved",
TrueValue = "Y",
FalseValue = "N"
};
var changeReasonColumn = new DataGridViewComboBoxColumn
{
Name = "approved_category_combo",
DataPropertyName = "approved_category",
DataSource = this.ReasonData.DropDownItems
};
if (dgvReasons.Columns["approved_check"] == null)
{
dgvReasons.Columns.Insert(0, approvedColumn);
}
if (dgvReasons.Columns["approved_category_combo"] == null)
{
dgvReasons.Columns.Insert(1, changeReasonColumn);
}
dgvReasons.Columns["note"].HeaderText = "Note";
dgvReasons.Columns["note"].DefaultCellStyle.WrapMode = DataGridViewTriState.True;
dgvReasons.Columns["note"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dgvReasons.Columns["buyer_name"].HeaderText = "Buyer";
dgvReasons.Columns["buyer_name"].Width = 80;
dgvReasons.Columns["location_id"].HeaderText = "Loc";
dgvReasons.Columns["location_id"].Width = 50;
dgvReasons.Columns["item_id"].HeaderText = "Item Id";
dgvReasons.Columns["reason_category"].HeaderText = "Original Category";
dgvReasons.Columns["approved_category_combo"].HeaderText = "Approved Category";
dgvReasons.Columns["approved_category_combo"].Width = 125;
dgvReasons.Columns["approved_check"].HeaderText = "Approve";
dgvReasons.Columns["approved_check"].Width = 50;
dgvReasons.Columns["stockout_reason_uid"].Visible = false;
dgvReasons.Columns["date_created"].Visible = false;
dgvReasons.Columns["buyer_id"].Visible = false;
dgvReasons.Columns["date_last_modified"].Visible = false;
dgvReasons.Columns["approved"].Visible = false;
dgvReasons.Columns["approved_category"].Visible = false;
foreach (var col in dgvReasons.Columns.Cast<DataGridViewColumn>().Where(col => !col.Name.Contains("approved")))
{
col.ReadOnly = true;
}
}
}
}
BUSINESS LOGIC
using System;
using System.Data;
namespace StockoutReasonReview
{
class ReasonData
{
public DataTable ReasonTable { get; set; }
public readonly string[] DropDownItems =
{
"",
"New Item",
"Supplier Issue",
"Carrier Issue",
"Didn't Order/Transfer in time",
"Sales Spike",
"Large Qty Order",
"Other"
};
public ReasonData()
{
this.ReasonTable = new DatabaseTransaction().GetReasons();
GenerateAdditionalColumns();
PopulateCategories();
}
public void Submit()
{
new DatabaseTransaction().SubmitReasons(this.ReasonTable);
}
private void GenerateAdditionalColumns()
{
this.ReasonTable.Columns.Add("approved"); //Temp column to be used during approval process
//this.ReasonTable.Columns.Add("approved_category"); //Testing Only - Need to add the column to the actual database after today's reviews are complete
}
private void PopulateCategories()
{
foreach (DataRow row in this.ReasonTable.Rows)
{
row["approved_category"] = row["approved_category"] == DBNull.Value
? row["reason_category"]
: row["approved_category"];
}
}
}
}
DATA ACCESS
using System;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using StockoutReasonReview.Properties;
using WPD_Common_Library;
namespace StockoutReasonReview
{
public class DatabaseTransaction
{
public DataTable GetReasons()
{
using (var dt = new DataTable())
using (var conn = new SqlConnection(ConnectionStrings.P21ConnectionString))
using (var cmd = new SqlCommand(Resources.GetReasonString, conn))
{
conn.Open();
dt.Load(cmd.ExecuteReader());
return dt;
}
}
public void SubmitReasons(DataTable dtSubmit)
{
foreach (var row in dtSubmit.Rows.Cast<DataRow>().Where(row => row["approved"].ToString() == "Y"))
{
using (var conn = new SqlConnection(ConnectionStrings.P21ConnectionString))
using (var cmd = new SqlCommand(Resources.SubmitReasonString, conn))
{
cmd.Parameters.AddWithValue("@Uid", row["stockout_reason_uid"]);
cmd.Parameters.AddWithValue("@Category", row["approved_category"]);
cmd.Parameters.AddWithValue("@Modified", DateTime.Now);
conn.Open();
cmd.ExecuteNonQuery();
}
}
}
}
}
Obviously I am open to other suggestions in a more general sense, but I am specifically focused on my question regarding further decoupling.