Lightweight Replacement for System.Data.DataTable - c#

There is tabular data that is being stored in the database as a delimited data. Not ideal, I know, but that's how the system was designed. I need to pull the data out and parse it into some kind of structure.
In the old days, I'd use a DataTable and call it good. Now, however, that just feels dirty. What is a better, more efficient, and more lightweight structure to store tabular data in my data model?

Here's a lightweight DataTable from one of the Telerik developers:
http://blogs.telerik.com/vladimirenchev/posts/09-04-23/lightweight-datatable-for-your-silverlight-applications.aspx
It supports INotifyCollectionChanged and INotifyPropertyChanged so it works well for data binding.
I wouldn't say it's any less "dirty", but it is an alternative.

Well, just create a class that has all the columns of the database as properties. Then just instantiate an implementation of ICollection (List, Hashset, etc..) and fill it (using LINQ for example).
public class Customer
{
public int Id { get; set;}
public string Name { get; set; }
public Customer(int id, string name)
{
this.Id = id;
this.Name = name;
}
}
And do something like:
List<Customer> customers = new List<Customer>();
using (DbDataReader reader = // instantiate reader)
{
while (reader.Read())
{
Customer customer = new Customer(reader.GetInt32(0), reader.GetString(1));
customers.Add(customer);
}
}
If you are accessing data that is stored in a database you may want to look at LinqToSql or LinqToEntities.

Well use a library i developed it include type to type convert and many more, and datareader to list
https://www.nuget.org/packages/Generic.LightDataTable/

Related

Update all Fields passed in object without using replace

I'm writing a wrapper around certain functions of mongodb to enforce certain buisiness policies (such as having a last modified date, a document version &c). These extra fields will not appear in the model and will be irrelevant and transparent to the person implementing against this library. This library will be generic.
Therefore using replaceOne is out of the question.
What I would like is some way of passing all fields in a person passed object to the Update builder - so I can use .Set/.Inc accordingly to add the other fields.
An example to demonstrate what I want is below:
public static async Task UpdatePerson(string name, Person person)
{
var client = new MongoClient("mongodb://localhost:27017");
IMongoDatabase db = client.GetDatabase("test");
IMongoCollection<Person> collection = db.GetCollection<Person>("people");
var query = Builders<Person>.Filter
.Eq("name", name);
var update = Builders<Person>.Update
//Something here - how do I pass my person's properties?
.Set("lastModified", DateTime.Now)
.Inc("version",1);
await collection.UpdateOneAsync(query, update );
}
//--
//In real life this'll work for other types, this is for demonstration only
public class Person
{
public string name {get;set;}
public string surname {get;set;}
}
So how can I go about this, without, for instance, looping through properties using Reflection?
Not sure if you are able to do this but the Mongodb Driver provides something called [BsonExtraElements].
public class Person
{
public string name {get;set;}
public string surname {get;set;}
[BsonExtraElements]
public Dictionary<string,object> AdditionalFields { get; set; }
}
What will happen is that anything that cant be serialized to the model will be filled into that dictionary, no matter the type. You can add to it as well and remove.
This will add no additional overhead to your database, The only downside to this is that querying this dictionary is somewhat not a great experience as you may need to cast specific keys to their relevant expected types.
If this is not viable I suggest the BSON approach recommended by Simon.

C# Comparing complex objects returning list of differences

I've been working on a project for a while to parse a list of entries from a csv file and use that data to update a database.
For each entry I create a new user instance that I put in a collection. Now I want to iterate that collection and compare the user entry to the user from the database (if it exists). My question is, how can I compare that user (entry) object to the user (db) object, while returning a list with differences?
For example following classes generated from database:
public class User
{
public int ID { get; set; }
public string EmployeeNumber { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Nullable<int> OfficeID { get; set; }
public virtual Office Office { get; set; }
}
public class Office
{
public int ID { get; set; }
public string Code { get; set; }
public virtual ICollection<User> Users { get; set; }
}
To save some queries to the database, I only fill the properties that I can retrieve from the csv file, so the ID's (for example) are not available for the equality check.
Is there any way to compare these objects without defining a rule for each property and returning a list of properties that are modified? I know this question seems similar to some earlier posts. I've read a lot of them but as I'm rather inexperienced at programming, I'd appreciate some advice.
From what I've gathered from what I've read, should I be combining 'comparing properties generically' with 'ignoring properties using data annotations' and 'returning a list of CompareResults'?
There are several approaches that you can solve this:
Approach #1 is to create separate DTO-style classes for the contents of the CSV files. Though this involves creating new classes with a lot of similar fields, it decouples the CSV file format from your database and gives you the ability to change them later without influencing the other part. In order to implement the comparison, you could create a Comparer class. As long as the classes are almost identical, the comparison can get all the properties from the DTO class and implement the comparison dynamically (e.g. by creating and evaluating a Lambda expression that contains a BinaryExpression of type Equal).
Approach #2 avoids the DTOs, but uses attributes to mark the properties that are part of the comparison. You'd need to create a custom attribute that you assign to the properties in question. In the compare, you analyze all the properties of the class and filter out the ones that are marked with the attribute. For the comparison of the properties you can use the same approach as in #1. Downside of this approach is that you couple the comparison logic tightly with the data classes. If you'd need to implement several different comparisons, you'd clutter the data classes with the attributes.
Of course, #1 results in a higher effort than #2. I understand that it is not what you are looking for, but maybe having a separate, strongly-typed compared class is also an approach one can think about.
Some more details on a dynamic comparison algorithm: it is based on reflection to get the properties that need to be compared (depending on the approach you get the properties of the DTO or the relevant ones of the data class). Once you have the properties (in case of DTOs, the properties should have the same name and data type), you can create a LamdaExpression and compile and evaluate it dynamically. The following lines show an excerpt of a code sample:
public static bool AreEqual<TDTO, TDATA>(TDTO dto, TDATA data)
{
foreach(var prop in typeof(TDTO).GetProperties())
{
var dataProp = typeof(TDATA).GetProperty(prop.Name);
if (dataProp == null)
throw new InvalidOperationException(string.Format("Property {0} is missing in data class.", prop.Name));
var compExpr = GetComparisonExpression(prop, dataProp);
var del = compExpr.Compile();
if (!(bool)del.DynamicInvoke(dto, data))
return false;
}
return true;
}
private static LambdaExpression GetComparisonExpression(PropertyInfo dtoProp, PropertyInfo dataProp)
{
var dtoParam = Expression.Parameter(dtoProp.DeclaringType, "dto");
var dataParam = Expression.Parameter(dataProp.DeclaringType, "data");
return Expression.Lambda(
Expression.MakeBinary(ExpressionType.Equal,
Expression.MakeMemberAccess(
dtoParam, dtoProp),
Expression.MakeMemberAccess(
dataParam, dataProp)), dtoParam, dataParam);
}
For the full sample, see this link. Please note that this dynamic approach is just an easy implementation that leaves room for improvement (e.g. there is no check for the data type of the properties). It also does only check for equality and does not collect the properties that are not equal; but that should be easy to transfer.
While the dynamic approach is easy to implement, the risk for runtime errors is bigger than in a strongly-typed approach.

Using Dapper to bind with a strongly typed model with additional dynamic properties

We are hopefully moving over to use Dapper to provide the object relation mapping to our business models.
Along with these data models, we often encounter custom fields (not known at runtime) which are created by users and appear as part of the returned result set:
Id
Title
c_MyCustomField1
c_MyCustomField2
Currently, all these fields are returned and handled with a reader. We like to move all this over to Dapper but struggling to work out how to mix the strongly typed object mixed with dynamic custom fields.
We see our options like this:
Get every result from dapper as dynamic and do our own binding.
Get Dapper to bind to the strongly typed model and make a separate call to attach the custom fields.
Extend Dapper to get in the middle add our specific user case to bind both the known and dynamic fields.
1 seems counterproductive and we'll possibly take a performance hit which is why you'd introduce Dapper in the first place. 2 we really can't do as this would require a massive change to the data provider. 3 I know I don't belong in the source of Dapper.
I think the holy grail would be ending up with a model like this:
class Model
{
int Id {get; set;}
string Title {get; set;}
IList<CustomField> CustomFields {get; set;}
}
class CustomField : dynamic
{
string Name {get; set;}
object Value {get; set;}
}
Is there any way this could be done using Dapper?
As always, any suggestions greatly appreciated.
That can't be modeled cleanly in dapper currently; you might be able to do something with the non-generic API and then applying the bindings manually. Or maybe just wrap a dynamic:
class Model {
private dynamic obj;
public int Id { get { return obj.Id; } set { obj.Id = value; } }
public string Title { get { return obj.Title; } set { obj.Title = value; } }
public object this[string key] {
get { return ((IDictionary<string,object>)obj)[key]; }
set { ((IDictionary<string,object>)obj)[key] = value; }
}
}
You can get a dynamic / IDictionary<string,object> by using Query without specifying a generic parameter.

help with c# array

I have a datatable with two columns. I want to store the rows of each column in an array so that I can return rows for each individual column. This way I believe I can populate a list box(the option text as one column and the option value as the other column).
Here is what I started out with:
public object dbAccess2()
{
ArrayList arg = new ArrayList();
DataTable myTable = GenericDataAccess.ExecuteSelectCmd("Vehicle_GetMakes");
foreach (DataRow dRow in myTable.Rows)
{
arg.Add(dRow["VehicleMake"]);
arg.Add(dRow["VehicleMakeId"]);
}
return arg.ToArray();
}
You can make a class to hold each individual row in this case and use a List<T> to hold the data, like this:
public class Vehicle
{
public string Make { get, set };
public string MakeId { get, set };
}
..
List<Vehicle> Vehicles = new List<Vehicle>();
..
foreach (DataRow dRow in myTable.Rows)
{
Vehicles.Add(
new Vehicle {
Make = arg.Add(dRow["VehicleMake"]),
MakeId = arg.Add(dRow["VehicleMakeId"])
});
}
And later, you can easily populate a listbox with this list:
listBox.DataSource = Vehicles;
listBox.DisplayMember = "Make";
But I think you may want to use a ListView probably.
Don't use the ArrayList class, it's practically obsolete. Use arrays or generic lists instead, so that you get a typed result.
You can get the columns into lists like this:
List<string> makes = myTable.Rows.Select(r => (string)r["VehicleMake"]).ToList();
List<int> makeIds = myTable.Rows.Select(r => (int)r["VehicleMakeId"]).ToList();
Or into arrays:
string[] makes = myTable.Rows.Select(r => (string)r["VehicleMake"]).ToArray();
int[] makeIds = myTable.Rows.Select(r => (int)r["VehicleMakeId"]).ToArray();
An alternative to populating a dropdown (as that is what I assume that you mean, as a ListBox doesn't have options) from arrays is to use data binding:
theDropdown.DataTextField = "VehicleMake";
theDropdown.DataValueField = "VehicleMakeId";
theDropdown.DataSource = myTable;
theDropdown.DataBind();
What you're attempting is to manipulate real objects without the benefit of object design, invoking raw data instead. This has very broad and far-reaching problems and is quite far behind current development strategies - to broad to go into here but not least of your problems is building in a brittle coupling between your application and your database.
Step one is to model an actual Vehicle class.
public class Vehicle
{
public string MakeId { get; set; }
public string Make { get; set; }
}
Step two is to build a managing class for your Vehicles ("Fleet" perhaps?) which can abstract the Vehicle collection behind an IEnumerable interface. Internally you will store the Vehicles collection as a concrete generic collection (a List or Dictionary most likely) and avoid at all costs the really-should-be-considered-obsolete ArrayList structure.
public class Fleet
{
private List<Vehicle> _vehicles = new List<Vehicle>();
public IEnumerable<Vehicle> Vehicles { return this._vehicles;}
}
Step three is to internalise to this class (or a class behind this one or behind that one etc, etc) the CRUD operations which will interact with the Database stored data. That's truly an implementation detail, but one you'll apply for all similar classes throughout your architecture.
At this point you'll be able to work with the IEnumerable property directly with standard Databinding methods.

Possible ways to return a subset of data from Repository<T>?

Let's say I need to display a list of customers, but only want to display the Name and somehow associate the key to the name within a list control.
It would probably be costly to retrieve the entire list of customers and all it's properties. In this scenario, would it be better to create another class with the properties that are required (in this case Id and Name)?
A basic implementation could look like this:
public class Customer {
public int Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public int Age { get; set; }
.....
}
public class CustomerListView {
public int Id { get; set; }
public string Name { get; set; }
}
public interface IRepository<T> {
public T Find(int id);
public IEnumerable<T> FindAll();
....
}
public class Repository<T>: IRepository<T> {
....
}
public class CustomerRepository: Repository<Customer> {
public IEnumerable<CustomerListView> FindAllListView();
}
Would this approach be appropriate? What other options would there be?
In order to achieve such goals, I create a simple 'View' class, for example CustomerView, which just contains the properties that are needed to display an overview.
My Repository then has a method which returns a collection of these CustomerView objects.
I mostly use NHibernate in my projects. Nhibernate allows you to use 'projections'.
So, what I do in my repository is this:
(note that the code below is just some pseudo-code; it won't compile).
public IList<CustomerView> GetAllCustomers()
{
ICriteria crit = _session.CreateCriteria (typeof(Customer));
crit.AddProjection ( ... );
crit.SetResultTransformer (new EntityToBeanTransformer(typeof(CustomerView));
return crit.ToList();
}
In fact, it comes down to this: I tell my O/R mapper that it should query Customers, but that it should return entities of type 'CustomerView'.
In the defintion of the projection, I also define which properties of the Customer class map to which properties of the CustomerView class.
Then, the O/R mapper is smart enough to generate a very simple query, which only retrieves those fields that are required to populate the CustomerView class.
For instance, the query that is executed can be as simple as:
SELECT customerid, customername FROM tblCustomer
If you use IQueryable as your return instead of IEnumerable than there is no cost of doing:
CustomerRepository().GetAll().Find(1) because AsQueryable doesn't actually execute until you request data. That means LINQ can optimize it out to a:
SELECT .... FROM .... WHERE ID = 1 instead of
GET EVERYTHING. FIND WHERE THE ID = 1
See this post for an explanation:
Why use AsQueryable() instead of List()?
Using this approach you could create an anonymous class and futher narrow down the data going over the wire to just what you want. That way the query generated by LINQ is optimized to the fullest.
If you have to retrieve the list form a Database then your proposal makes some sense but I would look into a Linq and anonymous type solution.
If the list of Customers already exists in memory then there there are no savings.
You could combine the techniques used by Nissan and Frederik (anonymous types and NHibernate) by using Linq-to-NHibernate.
Item #31 in Bill Wagner's More Effective C# says "limit type scope by using anonymous types", and I agree. BTW, I recommend the whole book.

Categories