I followed the article here and the sample code given in it.
What I am trying to implement is pretty straightfoward. I do have a fair understanding about collections and enumerators. However, what I don't understand is that even though there is hardly any difference in the way I have implemented the code as compared to how it is implemented in the given article, why I am getting an error.
Only difference in the implementation is that the sample code uses T (generic) whereas I am using a class named Address while implementing the custom Addresses collection class.
The code is pretty straightfoward. I have the following classes in the project.
Contact class
Addresses class (Implements custom collection and inherits from ICollection)
Address class
AddressEnumerator
What I wish to achieve is the Dataset like functionality where we can use a syntax like:
Dataset ds = new Dataset();
Ds.Tables[0]....blah blah blah.
I get a compile time error in the following method of the AddressEnumerator.cs class.
Error:
cannot apply indexing with [] to an expression of type ConsoleApplication2.Addresses (Addresses class implements an ICollection)
Compile time error occurs in the following statement:
_current = _collection[index];
public bool MoveNext()
{
if(++index >= _collection.Count)
{
return false;
}
else
{
_current = _collection[index];
}
return true;
}
Source code:
//following code snippet does not traverse the collection
foreach (Address a in c.Addresses)
{
Console.WriteLine(a.Street);
}
Program.cs
using System;
using System.Configuration;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
//RenderTimeSheet();
Address ad = new Address();
ad.Street = "Hollywood";
ad.City = "LA";
ad.State = "California";
ad.ZipCode = "93494";
ad.Country = "USA";
using (Contact c = new Contact(ad))
{
c.FirstName = "John";
c.LastName = "Doe";
Console.WriteLine(c.FirstName);
Console.WriteLine(c.LastName);
foreach (Address a in c.Addresses)
{
Console.WriteLine(a.Street);
}
}
Console.ReadKey();
}
}
Contact.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
namespace ConsoleApplication2
{
public class Contact : IDisposable
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Addresses Addresses { get; set; }
public Contact(Address a)
{
Addresses = new Addresses(a);
}
public Contact()
{
}
public void Dispose()
{
Console.Write("Disposing off...");
}
}
}
Addresses.cs
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
public class Addresses : ICollection<Address>
{
private IList<Address> _lstAddress;
protected bool _IsReadOnly;
public Addresses(Address _a)
{
_lstAddress = new List<Address>();
}
public void Add(Address item)
{
_lstAddress.Add(item);
}
public void Clear()
{
_lstAddress.Clear();
}
public bool Contains(Address item)
{
foreach(Address a in _lstAddress)
{
if(a.Street == item.Street)
{
return true;
}
}
return false;
}
public void CopyTo(Address[] array, int arrayIndex)
{
throw new Exception("Not valid for this implementation.");
}
public int Count
{
get { return _lstAddress.Count; }
}
public bool IsReadOnly
{
get { return _IsReadOnly; }
}
public bool Remove(Address item)
{
bool result = false;
for (int i = 0; i < _lstAddress.Count; i++)
{
Address obj = (Address)_lstAddress[i];
if(obj.Street == item.Street)
{
_lstAddress.RemoveAt(i);
result = true;
break;
}
}
return result;
}
public IEnumerator<Address> GetEnumerator()
{
return new AddressEnumerator(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
//throw new NotImplementedException();
return this.GetEnumerator();
}
}
}
Address.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
}
}
AddressEnumerator.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
public class AddressEnumerator : IEnumerator<Address>
{
protected Addresses _collection;
protected int index;
protected Address _current;
public AddressEnumerator()
{
}
public AddressEnumerator(Addresses collection)
{
_collection = collection;
index = -1;
_current = default(Address);
}
public Address Current
{
get
{
return _current;
}
}
public void Dispose()
{
_collection = null;
_current = default(Address);
index = -1;
}
object System.Collections.IEnumerator.Current
{
get
{
return _current;
}
}
public bool MoveNext()
{
if(++index >= _collection.Count)
{
return false;
}
else
{
_current = _collection[index];
}
return true;
}
public void Reset()
{
throw new NotImplementedException();
}
}
}
this is a direct and short solution to your problem,
but it is not a "complete clean" solution, also the coding style of the complete implementation should be changed. there are more effective ways implementing enumerable interfaces ...
change the line
_current = _collection[index];
to
_current = _collection._lstAddress[index];
but you also need to change the access modifier
private IList<Address> _lstAddress
for example to
internal IList<Address> _lstAddress
The reason that the sample code works and yours doesn't is because the sample code class BusinessObjectCollection includes this:
public virtual T this[int index]
{
get
{
return (T)_innerArray[index];
}
set
{
_innerArray[index] = value;
}
}
which provides the subscript operator [] that your code lacks.
If you add that to your Addresses class (changing _innerArray to _lstAddress) then it should work, I think.
Related
I'm situation really tricky. I need test if the UseDeveloperExceptionPage middleware is being called when an exception is thrown.
As an attempt to achieve that goal I wrote a bunch of ancillary code.
DiagnosticExceptionAssembly.cs
namespace TestProjectSample
{
internal static class DiagnosticExceptionAssembly
{
internal const string Assembly = "Microsoft.AspNetCore.Diagnostics.UnhandledException";
}
}
ExceptionMessage.cs
namespace TestProjectSample
{
public struct ExceptionMessage
{
public string Message { get; set; }
}
}
ExceptionMessageObserver.cs
using System;
namespace TestProjectSample
{
public class ExceptionMessageObserver : IExceptionMessage
{
public string Message { get; set; }
public void OnCompleted()
{
throw new NotImplementedException();
}
public void OnError(Exception error)
{
throw new NotImplementedException();
}
public void OnNext(ExceptionMessage value)
{
Message = value.Message;
}
}
public interface IExceptionMessage : IObserver<ExceptionMessage>
{
string Message { get; set; }
}
}
ExceptionObserver.cs
using System;
using System.Collections.Generic;
using System.Reflection;
namespace TestProjectSample
{
public class ExceptionObserver : IObserver<KeyValuePair<string, object>>
{
private readonly IObserver<ExceptionMessage> _exceptionMessage;
public ExceptionObserver(IObserver<ExceptionMessage> exceptionMessage)
{
_exceptionMessage = exceptionMessage;
}
public void OnCompleted()
{
throw new NotImplementedException();
}
public void OnError(Exception error)
{
throw new NotImplementedException();
}
public void OnNext(KeyValuePair<string, object> value)
{
switch (value.Key)
{
case DiagnosticExceptionAssembly.Assembly:
var exceptionPayload = value.Value
.GetType()
.GetTypeInfo()
.GetDeclaredProperty("Exception")?
.GetValue(value.Value) as string;
_exceptionMessage.OnNext(new ExceptionMessage {Message = exceptionPayload});
break;
}
}
}
}
ExceptionSubscriber.cs
using System;
using System.Diagnostics;
namespace TestProjectSample
{
public class ExceptionSubscriber : IObserver<DiagnosticListener>
{
private readonly IObserver<ExceptionMessage> _exceptionMessage;
public ExceptionSubscriber(IObserver<ExceptionMessage> exceptionMessage)
{
_exceptionMessage = exceptionMessage;
}
public void OnCompleted()
{
throw new NotImplementedException();
}
public void OnError(Exception error)
{
throw new NotImplementedException();
}
public void OnNext(DiagnosticListener value)
{
if (string.Equals(DiagnosticExceptionAssembly.Assembly, value.Name))
{
value.Subscribe(new ExceptionObserver(_exceptionMessage));
}
}
}
}
DevExceptionPageFacts.cs
using System.Diagnostics;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Hosting;
using Xunit;
namespace TestProjectSample
{
public class DevExceptionPageFacts
{
private readonly IHostBuilder _hostBuilder;
private static readonly IExceptionMessage ExceptionMessage = new ExceptionMessageObserver();
public DevExceptionPageFacts()
{
FactSubscriber();
_hostBuilder = GenerateExceptionHostBuilder();
}
private static IHostBuilder GenerateExceptionHostBuilder()
{
return new HostBuilder()
.ConfigureWebHost(builder =>
{
builder.UseTestServer();
builder.Configure(applicationBuilder =>
{
applicationBuilder.UseDeveloperExceptionPage();
applicationBuilder.Run(context => throw new HttpResetTestException(1));
});
});
}
private static void FactSubscriber()
{
DiagnosticListener.AllListeners.Subscribe(new ExceptionSubscriber(ExceptionMessage));
}
[Fact]
public async Task Throw_DevelopmentPageException()
{
var host = await _hostBuilder.StartAsync();
using var client = host.GetTestClient();
var response = await client.GetAsync("/");
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
Assert.NotNull(ExceptionMessage.Message);
}
}
}
Investigating the source code of UseDeveloperExceptionPage I have noted an injection of DiagnosticSource so that I have decided create a class to listen to when an exception is thrown and caught by middleware. However my test does not pass. Could anyone know how to make this test pass?
I have edited the question. Thanks for the comments below.
It looks like my issue was with a parameterless constructor to declare the class in XAML. However, I can't seem to figure out how to get a parameterless constructor with an observable collection. Please see my code below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace LinkKing.Classes
{
[Serializable()]
public class TheLinks
{
public string linkID;
public string parentID;
public string link;
public DateTime dateAdded;
public int stepAdded;
public string img;
[System.Xml.Serialization.XmlElement("Link")]
public string Link
{
get { return link; }
set { link = value; }
}
[System.Xml.Serialization.XmlElement("DateAdded")]
public DateTime DateAdded
{
get { return dateAdded; }
set { dateAdded = value; }
}
[System.Xml.Serialization.XmlElement("StepAdded")]
public int StepAdded
{
get { return stepAdded; }
set { stepAdded = value; }
}
[System.Xml.Serialization.XmlElement("LinkID")]
public string LinkID
{
get { return linkID; }
set { linkID = value; }
}
[System.Xml.Serialization.XmlElement("ParentID")]
public string ParentID
{
get { return parentID; }
set { parentID = value; }
}
[System.Xml.Serialization.XmlElement("IMG")]
public string IMG
{
get { return img; }
set { img = value; }
}
public TheLinks(string linkID, string parentID, string link, DateTime dateAdded, int stepAdded, string img) : base()
{
this.Link = link;
this.DateAdded = dateAdded;
this.StepAdded = stepAdded;
this.LinkID = linkID;
this.ParentID = parentID;
this.IMG = img;
}
}
public class MyLinks : ObservableCollection<TheLinks>
{
public MyLinks() : base()
{
}
}
}
The error I get is The Type does not include any accessible constructors.
I appreciate everyone's help.
Just based on the code, you have no public parameterless constructor for MyLinks. If you did you would find it on local.
Also usually if it's MVVM, I think having a different namespace for the ViewModel would be better.
Maybe it would also make sense to make your fields (i.e. public string linkID;public string parentID; up to public string img;) private too since you don't access them from outside the class anyway.
I'm creating a Xamarin.Forms Portable Application wherein I was able to display a Pie Chart using OxyPlot. My chart only has pre-defined items. What I want to do is to make the items from my DATABASE in Visual Studio to be displayed on the Chart and not the pre-defined items.
I have 2 projects in one Solution. The WebFormsProject and the Xamarin.Forms (Portable)
In my WebFormsProject, I created a SalesController where I used LINQ expression to get all the data in the database that I need. I also created a SalesViewModel there where I have declared all the Properties I have. I tried to test it in my WEB API if it does return a value or not, and IT DOES RETURN A VALUE.
In my PORTABLE project, I have a created Sales model that has exactly the same Properties with my SalesViewModel in the WebFormsProject. I also have a SalesVM.cs wherein I tried to access the records from the WebFormsProject by using SalesServices and RestClient.
I have tried using these codes but it didn't work. What do you think is the reason behind this?
Here are my codes:
WebForms
1.) SalesViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebFormsDemo.ViewModel
{
public class SalesViewModel
{
public int Id { get; set; }
public int ORDER_ID { get; set; }
public int ORDER_DETAILS_ID { get; set; }
public int PRODUCT_ID { get; set; }
public string PRODUCT_CODE { get; set; }
public string NET_AMOUNT { get; set; }
}
}
2.) SalesController.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Description;
using WebFormsDemo;
using WebFormsDemo.ViewModel;
namespace WebFormsDemo.Controllers
{
public class SalesController : ApiController
{
private EBMSEntities db = new EBMSEntities();
// GET: api/Sales
public IQueryable<SalesViewModel> GetSalesViewModels()
{
//return db.SalesViewModels;
var sales = from order in db.ORDERs
join order_detail in db.ORDER_DETAILS
on order.ORDER_ID equals order_detail.ORDER_ID
join prod in db.PRODUCTs
on order_detail.PRODUCT_ID equals prod.PRODUCT_ID
orderby order_detail.TOTAL_AMT_PER_ITEM descending
//group prod by prod.PRODUCT_CODE
group order_detail by prod.PRODUCT_CODE into od
select new SalesViewModel
{
PRODUCT_CODE = od.Key,
NET_AMOUNT = od.Sum(p => p.TOTAL_AMT_PER_ITEM).ToString(),
};
return sales;
}
// GET: api/Sales/5
[ResponseType(typeof(SalesViewModel))]
public IHttpActionResult GetSalesViewModel(int id)
{
SalesViewModel salesViewModel = db.SalesViewModels.Find(id);
if (salesViewModel == null)
{
return NotFound();
}
return Ok(salesViewModel);
}
// PUT: api/Sales/5
[ResponseType(typeof(void))]
public IHttpActionResult PutSalesViewModel(int id, SalesViewModel salesViewModel)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != salesViewModel.Id)
{
return BadRequest();
}
db.Entry(salesViewModel).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!SalesViewModelExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Sales
[ResponseType(typeof(SalesViewModel))]
public IHttpActionResult PostSalesViewModel(SalesViewModel salesViewModel)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.SalesViewModels.Add(salesViewModel);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = salesViewModel.Id }, salesViewModel);
}
// DELETE: api/Sales/5
[ResponseType(typeof(SalesViewModel))]
public IHttpActionResult DeleteSalesViewModel(int id)
{
SalesViewModel salesViewModel = db.SalesViewModels.Find(id);
if (salesViewModel == null)
{
return NotFound();
}
db.SalesViewModels.Remove(salesViewModel);
db.SaveChanges();
return Ok(salesViewModel);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool SalesViewModelExists(int id)
{
return db.SalesViewModels.Count(e => e.Id == id) > 0;
}
}
}
.
XamarinFormsPortable
1.) Sales.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XamarinFormsDemo.Models
{
public class Sales
{
public int Id { get; set; }
public int ORDER_ID { get; set; }
public int ORDER_DETAILS_ID { get; set; }
public int PRODUCT_ID { get; set; }
public string PRODUCT_CODE { get; set; }
public double NET_AMOUNT { get; set; }
}
}
2.) SalesVM.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OxyPlot;
using OxyPlot.Series;
using OxyPlot.Xamarin.Forms;
using Xamarin.Forms;
using System.Runtime.CompilerServices;
using XamarinFormsDemo.Models;
using System.Collections.ObjectModel;
using XamarinFormsDemo.Services;
namespace XamarinFormsDemo.ViewModels
{
public class SalesVM
{
private List<Sales> salesmodel { get; set; }
public List<Sales> SalesModelvm
{
get
{
return salesmodel;
}
set
{
salesmodel = value;
OnPropertyChanged();
}
}
public SalesVM()
{
InitializeDataAsync();
}
private async Task InitializeDataAsync()
{
var salesServices = new SalesServices();
SalesModelvm = await salesServices.GetSalesAsync();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
3.) SalesServices.cs
using Plugin.RestClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XamarinFormsDemo.Models;
namespace XamarinFormsDemo.Services
{
public class SalesServices
{
public async Task<List<Sales>> GetSalesAsync()
{
RestClient_Sales<Sales> restClient = new RestClient_Sales<Sales>();
var salesList = await restClient.GetSalesAsync();
return salesList;
}
}
}
4.) RestClient.cs
public class RestClient_Sales<T>
{
private const string WebServiceUrl = "http://localhost:50857/api/Sales/";
public async Task<List<T>> GetSalesAsync()
{
var httpClient = new HttpClient();
var json = await httpClient.GetStringAsync(WebServiceUrl);
var taskModels = JsonConvert.DeserializeObject<List<T>>(json);
return taskModels;
}
}
I got a code with a list which im trying to change to dictionary. my problem its that in 'BankRates.cs' i fail to add objects to my dictionary. i get error :no overload of method 'Add' takes 1 argument...can some explain why?? (i understand i should add a string to the function but when i try to add empty one to make it compile, the dictionary contains only one nonfunctional object)
i have this 4 cs files:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Converter
{
class Currency
{
//members
//getters and setters
public string Code { get; set; }
public string Name { get; set; }
public double Rate { get; set; }
public double Unit { get; set; }
public string Country { get; set; }
//constractor
public Currency(string code, string name, double rate, double unit, string country)
{
this.Code = code;
this.Name = name;
this.Rate = rate;
this.Unit = unit;
this.Country = country;
}
//override ToString method for visualization
public override string ToString()
{
return (Name + "-" +Code);
}
}
}
currencyDictionary:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Converter
{
class CurrencyDic
{
//setter and getter
public Dictionary<string,Currency> currencyDic { get; set; }
//constractor
public CurrencyDic()
{
currencyDic = new Dictionary<string,Currency>();
}
public CurrencyDic(Dictionary<string,Currency> cur)
{
currencyDic = new Dictionary<string,Currency>(cur);
}
// implements foreach
public IEnumerator<Currency> GetEnumerator()
{
foreach (Currency cur in currencyDic.Values) { yield return cur;}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Converter
{
interface IBankRates
{
void GetRates();
double Convert(Currency from, Currency to, double amount);
}
}
and the last one:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.IO;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Runtime.Remoting.Messaging;
namespace Converter
{
class BankRates:IBankRates
{
private string Bank_URL = "http://www.boi.org.il/currency.xml";
CurrencyDic currencyDic = new CurrencyDic();
public void GetRates()
{
XDocument xdoc = new XDocument();
try
{
xdoc = XDocument.Load(Bank_URL);}
catch (XmlException)
{
MessageBox.Show("Failed to load Xml file");
System.Environment.Exit(1);
}
//load the xml
var allCurencies = from currency in xdoc.Descendants("CURRENCY") //linq query
select new
{
Name = currency.Descendants("NAME").First().Value,
Unit = currency.Descendants("UNIT").First().Value,
Code = currency.Descendants("CURRENCYCODE").First().Value,
Cuntry = currency.Descendants("COUNTRY").First().Value,
Rate = currency.Descendants("RATE").First().Value
};
foreach (var currency in allCurencies)
{
currencyDic.currencyDic.Add(new Currency(currency.Code, currency.Name,
double.Parse(currency.Rate),
double.Parse(currency.Unit), currency.Cuntry));
}
}
//returns the list
public CurrencyDic getDic()
{
return currencyDic;
}
//makes the converting calculation
public double Convert(Currency from,Currency to, double amount)
{
double inRate, outRate, excangeRate;
inRate = from.Rate / from.Unit;
outRate = to.Rate / to.Unit;
excangeRate = inRate / outRate;
return (amount * excangeRate);
}
}
}
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.