I have recently come across a very simple Typed DataTable (without using a .XSD)(I've lost author's URL so I can't credit him) but it looks like there's a lot of duplicated code (Such as the Add/Remove/GetNewRow methods).
I've tried to push the repetitive methods into a super class, but I have issues due to the Employee needing to be generic. I was hoping to get StackOverflow's collective hive mind to suggest some ideas to clean this up? (If it's even possible at all?)
using System; using System.Data; using System.Collections; using System.Data.SqlClient; namespace TypedDataSet { public class Employees : DataTable { protected SqlDataAdapter _adapter; public Employees() { string connectionString = TypedDataSet.Properties.Settings.Default.ConnectionString; _adapter = new System.Data.SqlClient.SqlDataAdapter("SELECT Id, Firstname, Surname FROM Employee", connectionString); _adapter.Fill(this); } public Employee this[int index] { get { return (Employee)Rows[index]; } } public void Add(Employee row) { Rows.Add(row); } public void Remove(Employee row) { Rows.Remove(row); } public Employee GetNewRow() { Employee row = (Employee)NewRow(); return row; } protected override DataRow NewRowFromBuilder(DataRowBuilder builder) { return new Employee(builder); } public IEnumerator GetEnumerator() { return Rows.GetEnumerator(); } protected override Type GetRowType() { return typeof(Employee); } } public class Employee : DataRow { internal Employee(DataRowBuilder builder) : base(builder) { } public Int64 Id { get { return (Int64)base["Id"]; } set { base["Id"] = value; } } public string FirstName { get { return (string)base["Firstname"]; } set { base["Firstname"] = value; } } public string Surname { get { return (string)base["Surname"]; } set { base["Surname"] = value; } } } }
I believe that I've answered my question, kind of. I've had to use .net 4.0 to get the results that I was hoping for specificially the dynamic type.
So changing the existing class in the question:
Employee.cs
using System; using System.Data; using System.Collections; using System.Data.Common; namespace TypedDataSet { public class Employees : BaseModel<Employee> { public Employees(bool loadAll) { DbDataAdapter adapter = base.Adapter("SELECT * FROM Employees"); adapter.Fill(this); } protected override DataRow NewRowFromBuilder(DataRowBuilder builder) { return new Employee(builder); } } public class Employee : DataRow { internal Employee(DataRowBuilder builder) : base(builder) { } public Int64 Id { get { return (Int64)base["Id"]; } set { base["Id"] = value; } } public string FirstName { get { return (string)base["Firstname"]; } set { base["Firstname"] = value; } } public string Surname { get { return (string)base["Surname"]; } set { base["Surname"] = value; } } } }
And now introducing BaseModel that the above class inherits
BaseModel.cs
using System; using System.Data; using System.Collections; using System.Data.Common; using System.Data.SqlClient; namespace TypedDataSet { public class BaseModel<T> : DataTable { protected DbDataAdapter _adapter; protected string _connectionString = TypedDataSet.Properties.Settings.Default.ConnectionString; public BaseModel() { } protected DbDataAdapter Adapter(string sql) { _adapter = new System.Data.SqlClient.SqlDataAdapter(sql, _connectionString); SqlCommandBuilder cb = new SqlCommandBuilder((SqlDataAdapter)_adapter); return _adapter; } public dynamic this[int index] { get { return Rows[index]; } } public void Add(dynamic row) { Rows.Add(row); } public void Remove(dynamic row) { Rows.Remove(row); } public void Save() { _adapter.Update(this); this.AcceptChanges(); } public dynamic GetNewRow() { dynamic row = (dynamic)NewRow(); return row; } public IEnumerator GetEnumerator() { return Rows.GetEnumerator(); } protected override Type GetRowType() { return typeof(T); } } }
Which allows me to consume the class using the following code:
Employees employees = new Employees(true); Employee employee = employees.GetNewRow(); employee.FirstName = "Greg"; employee.Surname = "Focker"; employees.Add(employee); employees.Save(); foreach (Employee e in employees) { Console.WriteLine(e.FirstName + ' ' + e.Surname); }
I hope to evolve this further overtime so future StackOverflow users if you're interested in this little project take a look at http://bitbucket.org/Mozketo/typeddataset/ where I hope to host the code.