Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Case insensitive access to property names. #10

Closed
wants to merge 4 commits into from

2 participants

@schotime

Hey Rob,
Love the work so far, but I think with dynamic its hard enough getting the spelling correct let alone the case defined in the database, so I did a little hacking and came up with a solution. It is adding a new class that is basically mimicking ExpandoObject but you can't inherit from expandoObject so I had no choice.
Let me know what you think.
Cheers,
Adam

@robconery
Collaborator

Hi... yah I don't think I want to mirror ExpandoObject. Help with with the casing issue - is it the casing of the properties coming out of the db? Or...?

@schotime

Yeh, the properties coming out of the db. Especially for legacy dbs. You could also add convention naming using the new object, eg. db columns msg_id => MsgId etc.

@schotime

How did you do that eblackburn? Got some code?

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 22, 2011
  1. @schotime

    Created MassiveExpando to replace ExpandoObject so you can access col…

    schotime authored
    …umns in a case-insensitive manner. eg. table.Name or table.NAME or table name
  2. @schotime

    Reformatting

    schotime authored
  3. @schotime
  4. @schotime

    Minor cleanup

    schotime authored
This page is out of date. Refresh to see the latest.
Showing with 437 additions and 367 deletions.
  1. +436 −366 Massive.cs
  2. +1 −1  README.markdown
View
802 Massive.cs
@@ -1,367 +1,437 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Configuration;
-using System.Data;
-using System.Data.Common;
-using System.Dynamic;
-using System.Linq;
-using System.Text;
-using System.Collections;
-using System.Text.RegularExpressions;
-
-namespace Massive {
- public static class ObjectExtensions {
- /// <summary>
- /// Extension method for adding in a bunch of parameters
- /// </summary>
- public static void AddParams(this DbCommand cmd, object[] args) {
- foreach (var item in args) {
- AddParam(cmd, item);
- }
- }
- /// <summary>
- /// Extension for adding single parameter
- /// </summary>
- public static void AddParam(this DbCommand cmd, object item) {
- var p = cmd.CreateParameter();
- p.ParameterName = string.Format("@{0}", cmd.Parameters.Count);
- if (item == null) {
- p.Value = DBNull.Value;
- } else {
- if (item.GetType() == typeof(Guid)) {
- p.Value = item.ToString();
- p.DbType = DbType.String;
- p.Size = 4000;
- }else if(item.GetType()==typeof(ExpandoObject)){
- var d = (IDictionary<string, object>)item;
- p.Value = d.Values.FirstOrDefault();
- } else {
- p.Value = item;
- }
- //from DataChomp
- if (item.GetType() == typeof(string))
- p.Size = 4000;
- }
- cmd.Parameters.Add(p);
- }
- /// <summary>
- /// Turns an IDataReader to a Dynamic list of things
- /// </summary>
- public static List<dynamic> ToExpandoList(this IDataReader rdr) {
- var result = new List<dynamic>();
- while (rdr.Read()) {
- dynamic e = new ExpandoObject();
- var d = e as IDictionary<string, object>;
- for (int i = 0; i < rdr.FieldCount; i++)
- d.Add(rdr.GetName(i), rdr[i]);
- result.Add(e);
- }
- return result;
- }
- /// <summary>
- /// Turns the object into an ExpandoObject
- /// </summary>
- public static dynamic ToExpando(this object o) {
- var result = new ExpandoObject();
- var d = result as IDictionary<string, object>; //work with the Expando as a Dictionary
- if (o.GetType() == typeof(ExpandoObject)) return o; //shouldn't have to... but just in case
- if (o.GetType() == typeof(NameValueCollection)) {
- var nv = (NameValueCollection)o;
- nv.Cast<string>().Select(key => new KeyValuePair<string, object>(key, nv[key])).ToList().ForEach(i => d.Add(i));
- } else {
- var props = o.GetType().GetProperties();
- foreach (var item in props) {
- d.Add(item.Name, item.GetValue(o, null));
- }
- }
- return result;
- }
- /// <summary>
- /// Turns the object into a Dictionary
- /// </summary>
- public static IDictionary<string, object> ToDictionary(this object thingy) {
- return (IDictionary<string, object>)thingy.ToExpando();
- }
- }
- /// <summary>
- /// A class that wraps your database table in Dynamic Funtime
- /// </summary>
- public class DynamicModel {
- DbProviderFactory _factory;
- string _connectionString;
-
- public DynamicModel(string connectionStringName= "", string tableName = "", string primaryKeyField ="") {
- TableName = tableName == "" ? this.GetType().Name : tableName;
- PrimaryKeyField = string.IsNullOrEmpty(primaryKeyField) ? "ID" : primaryKeyField;
- if (connectionStringName == "")
- connectionStringName = ConfigurationManager.ConnectionStrings[0].Name;
- var _providerName = "System.Data.SqlClient";
- if (ConfigurationManager.ConnectionStrings[connectionStringName] != null) {
- if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName))
- _providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;
- } else {
- throw new InvalidOperationException("Can't find a connection string with the name '" + connectionStringName + "'");
- }
- _factory = DbProviderFactories.GetFactory(_providerName);
- _connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
- }
- /// <summary>
- /// Enumerates the reader yielding the result - thanks to Jeroen Haegebaert
- /// </summary>
- public IEnumerable<dynamic> Query(string sql, params object[] args) {
- using (var conn = OpenConnection()) {
- var rdr = CreateCommand(sql, conn, args).ExecuteReader(CommandBehavior.CloseConnection);
- while (rdr.Read()) {
- var e = new ExpandoObject();
- var d = e as IDictionary<string, object>;
- for (var i = 0; i < rdr.FieldCount; i++)
- d.Add(rdr.GetName(i), rdr[i]);
- yield return e;
- }
- }
- }
- /// <summary>
- /// Runs a query against the database
- /// </summary>
- public IList<dynamic> Fetch(string sql, params object[] args) {
- return Query(sql, args).ToList<dynamic>();
- }
- /// <summary>
- /// Returns a single result
- /// </summary>
- public object Scalar(string sql, params object[] args) {
- object result = null;
- using (var conn = OpenConnection()) {
- result = CreateCommand(sql, conn, args).ExecuteScalar();
- }
- return result;
- }
- /// <summary>
- /// Creates a DBCommand that you can use for loving your database.
- /// </summary>
- DbCommand CreateCommand(string sql, DbConnection conn, params object[] args) {
- DbCommand result = null;
- result = _factory.CreateCommand();
- result.Connection = conn;
- result.CommandText = sql;
- if (args.Length > 0)
- result.AddParams(args);
- return result;
- }
- /// <summary>
- /// Returns and OpenConnection
- /// </summary>
- public DbConnection OpenConnection() {
- var conn = _factory.CreateConnection();
- conn.ConnectionString = _connectionString;
- conn.Open();
- return conn;
- }
- /// <summary>
- /// Builds a set of Insert and Update commands based on the passed-on objects.
- /// These objects can be POCOs, Anonymous, NameValueCollections, or Expandos. Objects
- /// With a PK property (whatever PrimaryKeyField is set to) will be created at UPDATEs
- /// </summary>
- public List<DbCommand> BuildCommands(params object[] things) {
- var commands = new List<DbCommand>();
- foreach (var item in things) {
- if (HasPrimaryKey(item)) {
- commands.Add(CreateUpdateCommand(item,GetPrimaryKey(item)));
- }else{
- commands.Add(CreateInsertCommand(item));
- }
- }
-
- return commands;
- }
- /// <summary>
- /// Executes a set of objects as Insert or Update commands based on their property settings, within a transaction.
- /// These objects can be POCOs, Anonymous, NameValueCollections, or Expandos. Objects
- /// With a PK property (whatever PrimaryKeyField is set to) will be created at UPDATEs
- /// </summary>
- public int Save(params object[] things) {
- var commands = BuildCommands(things);
- return Execute(commands);
- }
- public int Execute(DbCommand command) {
- return Execute(new DbCommand[] { command });
- }
- /// <summary>
- /// Executes a series of DBCommands in a transaction
- /// </summary>
- public int Execute(IEnumerable<DbCommand> commands) {
- var result = 0;
- using (var conn = OpenConnection()) {
- using (var tx = conn.BeginTransaction()) {
- foreach (var cmd in commands) {
- cmd.Connection = conn;
- cmd.Transaction = tx;
- result+=cmd.ExecuteNonQuery();
- }
- tx.Commit();
- }
- }
- return result;
- }
- public string PrimaryKeyField { get; set; }
- /// <summary>
- /// Conventionally introspects the object passed in for a field that
- /// looks like a PK. If you've named your PrimaryKeyField, this becomes easy
- /// </summary>
- public bool HasPrimaryKey(object o) {
- return o.ToDictionary().ContainsKey(PrimaryKeyField);
- }
- /// <summary>
- /// If the object passed in has a property with the same name as your PrimaryKeyField
- /// it is returned here.
- /// </summary>
- public object GetPrimaryKey(object o) {
- object result = null;
- o.ToDictionary().TryGetValue(PrimaryKeyField, out result);
- return result;
- }
- public string TableName { get; set; }
- /// <summary>
- /// Creates a command for use with transactions - internal stuff mostly, but here for you to play with
- /// </summary>
- public DbCommand CreateInsertCommand(object o) {
- DbCommand result = null;
- var expando = o.ToExpando();
- var settings = (IDictionary<string, object>)expando;
- var sbKeys = new StringBuilder();
- var sbVals = new StringBuilder();
- var stub = "INSERT INTO {0} ({1}) \r\n VALUES ({2})";
- result = CreateCommand(stub,null);
- int counter = 0;
- foreach (var item in settings) {
- sbKeys.AppendFormat("{0},", item.Key);
- sbVals.AppendFormat("@{0},", counter.ToString());
- result.AddParam(item.Value);
- counter++;
- }
- if (counter > 0) {
- var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 1);
- var vals = sbVals.ToString().Substring(0, sbVals.Length - 1);
- var sql = string.Format(stub, TableName, keys, vals);
- result.CommandText = sql;
- } else throw new InvalidOperationException("Can't parse this object to the database - there are no properties set");
- return result;
- }
- /// <summary>
- /// Creates a command for use with transactions - internal stuff mostly, but here for you to play with
- /// </summary>
- public DbCommand CreateUpdateCommand(object o, object key) {
- var expando = o.ToExpando();
- var settings = (IDictionary<string, object>)expando;
- var sbKeys = new StringBuilder();
- var stub = "UPDATE {0} SET {1} WHERE {2} = @{3}";
- var args = new List<object>();
- var result = CreateCommand(stub,null);
- int counter = 0;
- foreach (var item in settings) {
- var val = item.Value;
- if (!item.Key.Equals(PrimaryKeyField, StringComparison.CurrentCultureIgnoreCase) && item.Value != null) {
- result.AddParam(val);
- sbKeys.AppendFormat("{0} = @{1}, \r\n", item.Key, counter.ToString());
- counter++;
- }
- }
- if (counter > 0) {
- //add the key
- result.AddParam(key);
- //strip the last commas
- var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 4);
- result.CommandText = string.Format(stub, TableName, keys, PrimaryKeyField, counter);
- } else throw new InvalidOperationException("No parsable object was sent in - could not divine any name/value pairs");
- return result;
- }
- /// <summary>
- /// Removes one or more records from the DB according to the passed-in WHERE
- /// </summary>
- public DbCommand CreateDeleteCommand(string where = "", object key = null, params object[] args) {
- var sql = string.Format("DELETE FROM {0} ", TableName);
- if (key != null) {
- sql += string.Format("WHERE {0}=@0", PrimaryKeyField);
- args = new object[]{key};
- } else if (!string.IsNullOrEmpty(where)) {
- sql += where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase) ? where : "WHERE " + where;
- }
- return CreateCommand(sql, null, args);
- }
- /// <summary>
- /// Adds a record to the database. You can pass in an Anonymous object, an ExpandoObject,
- /// A regular old POCO, or a NameValueColletion from a Request.Form or Request.QueryString
- /// </summary>
- public object Insert(object o) {
- dynamic result = 0;
- using (var conn = OpenConnection()) {
- var cmd = CreateInsertCommand(o);
- cmd.Connection = conn;
- cmd.ExecuteNonQuery();
- cmd.CommandText = "SELECT @@IDENTITY as newID";
- result = cmd.ExecuteScalar();
- }
- return result;
- }
- /// <summary>
- /// Updates a record in the database. You can pass in an Anonymous object, an ExpandoObject,
- /// A regular old POCO, or a NameValueCollection from a Request.Form or Request.QueryString
- /// </summary>
- public int Update(object o, object key) {
- return Execute(CreateUpdateCommand(o, key));
- }
- /// <summary>
- /// Removes one or more records from the DB according to the passed-in WHERE
- /// </summary>
- public int Delete(object key = null, string where = "", params object[] args) {
- return Execute(CreateDeleteCommand(where: where, key:key, args: args));
- }
- /// <summary>
- /// Returns all records complying with the passed-in WHERE clause and arguments,
- /// ordered as specified, limited (TOP) by limit.
- /// </summary>
- public IEnumerable<dynamic> All(string where = "", string orderBy = "", int limit = 0, string columns = "*", params object[] args) {
- string sql = limit > 0 ? "SELECT TOP " + limit + " {0} FROM {1} " : "SELECT {0} FROM {1} ";
- if (!string.IsNullOrEmpty(where))
- sql += where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase) ? where : "WHERE " + where;
- if (!String.IsNullOrEmpty(orderBy))
- sql += orderBy.Trim().StartsWith("order by", StringComparison.CurrentCultureIgnoreCase) ? orderBy : " ORDER BY " + orderBy;
- return Query(string.Format(sql, columns,TableName), args);
- }
-
- /// <summary>
- /// Returns a dynamic PagedResult. Result properties are Items, TotalPages, and TotalRecords.
- /// </summary>
- public dynamic Paged(string where = "", string orderBy = "", string columns = "*", int pageSize = 20, int currentPage =1, params object[] args) {
- dynamic result = new ExpandoObject();
- var countSQL = string.Format("SELECT COUNT({0}) FROM {1}", PrimaryKeyField, TableName);
- if (String.IsNullOrEmpty(orderBy))
- orderBy = PrimaryKeyField;
- var sql = string.Format("SELECT {0} FROM (SELECT ROW_NUMBER() OVER (ORDER BY {2}) AS Row, {0} FROM {3}) AS Paged ",columns,pageSize,orderBy,TableName);
- var pageStart = (currentPage -1) * pageSize;
- sql+= string.Format(" WHERE Row >={0} AND Row <={1}",pageStart, (pageStart + pageSize));
- var pagedWhere = "";
- if (!string.IsNullOrEmpty(where)) {
- if (where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase)) {
- pagedWhere = Regex.Replace(where, "where ", "and ", RegexOptions.IgnoreCase);
- }
- }
- sql += pagedWhere;
- countSQL += where;
- result.TotalRecords = Scalar(countSQL,args);
- result.TotalPages = result.TotalRecords / pageSize;
- if (result.TotalRecords % pageSize > 0)
- result.TotalPages += 1;
- result.Items = Query(string.Format(sql, columns, TableName), args);
- return result;
- }
- /// <summary>
- /// Returns a single row from the database
- /// </summary>
- public dynamic Single(object key, string columns = "*") {
- var sql = string.Format("SELECT {0} FROM {1} WHERE {2} = @0", columns,TableName, PrimaryKeyField);
- return Fetch(sql, key).FirstOrDefault();
- }
- }
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Configuration;
+using System.Data;
+using System.Data.Common;
+using System.Dynamic;
+using System.Linq;
+using System.Text;
+using System.Collections;
+using System.Text.RegularExpressions;
+
+namespace Massive {
+ public static class ObjectExtensions {
+ /// <summary>
+ /// Extension method for adding in a bunch of parameters
+ /// </summary>
+ public static void AddParams(this DbCommand cmd, object[] args) {
+ foreach (var item in args) {
+ AddParam(cmd, item);
+ }
+ }
+ /// <summary>
+ /// Extension for adding single parameter
+ /// </summary>
+ public static void AddParam(this DbCommand cmd, object item) {
+ var p = cmd.CreateParameter();
+ p.ParameterName = string.Format("@{0}", cmd.Parameters.Count);
+ if (item == null) {
+ p.Value = DBNull.Value;
+ } else {
+ if (item.GetType() == typeof(Guid)) {
+ p.Value = item.ToString();
+ p.DbType = DbType.String;
+ p.Size = 4000;
+ }else if(item.GetType()==typeof(MassiveExpando)){
+ var d = (IDictionary<string, object>)item;
+ p.Value = d.Values.FirstOrDefault();
+ } else {
+ p.Value = item;
+ }
+ //from DataChomp
+ if (item.GetType() == typeof(string))
+ p.Size = 4000;
+ }
+ cmd.Parameters.Add(p);
+ }
+ /// <summary>
+ /// Turns an IDataReader to a Dynamic list of things
+ /// </summary>
+ public static List<dynamic> ToExpandoList(this IDataReader rdr) {
+ var result = new List<dynamic>();
+ while (rdr.Read()) {
+ dynamic e = new MassiveExpando();
+ var d = e as IDictionary<string, object>;
+ for (var i = 0; i < rdr.FieldCount; i++)
+ d.Add(rdr.GetName(i), rdr[i]);
+ result.Add(e);
+ }
+ return result;
+ }
+ /// <summary>
+ /// Turns the object into an MassiveExpando
+ /// </summary>
+ public static dynamic ToExpando(this object o) {
+ var result = new MassiveExpando();
+ var d = result as IDictionary<string, object>; //work with the Expando as a Dictionary
+ if (o.GetType() == typeof(MassiveExpando)) return o; //shouldn't have to... but just in case
+ if (o.GetType() == typeof(NameValueCollection)) {
+ var nv = (NameValueCollection)o;
+ nv.Cast<string>().Select(key => new KeyValuePair<string, object>(key, nv[key])).ToList().ForEach(i => d.Add(i));
+ } else {
+ var props = o.GetType().GetProperties();
+ foreach (var item in props) {
+ d.Add(item.Name, item.GetValue(o, null));
+ }
+ }
+ return result;
+ }
+ /// <summary>
+ /// Turns the object into a Dictionary
+ /// </summary>
+ public static IDictionary<string, object> ToDictionary(this object thingy) {
+ return (IDictionary<string, object>)thingy.ToExpando();
+ }
+ }
+ /// <summary>
+ /// A class that wraps your database table in Dynamic Funtime
+ /// </summary>
+ public class DynamicModel {
+ DbProviderFactory _factory;
+ string _connectionString;
+
+ public DynamicModel(string connectionStringName = "", string tableName = "", string primaryKeyField = "") {
+ TableName = tableName == "" ? this.GetType().Name : tableName;
+ PrimaryKeyField = string.IsNullOrEmpty(primaryKeyField) ? "ID" : primaryKeyField;
+ if (connectionStringName == "")
+ connectionStringName = ConfigurationManager.ConnectionStrings[0].Name;
+ var _providerName = "System.Data.SqlClient";
+ if (ConfigurationManager.ConnectionStrings[connectionStringName] != null) {
+ if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName))
+ _providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;
+ } else {
+ throw new InvalidOperationException("Can't find a connection string with the name '" + connectionStringName + "'");
+ }
+ _factory = DbProviderFactories.GetFactory(_providerName);
+ _connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
+ }
+ /// <summary>
+ /// Enumerates the reader yielding the result - thanks to Jeroen Haegebaert
+ /// </summary>
+ public IEnumerable<dynamic> Query(string sql, params object[] args) {
+ using (var conn = OpenConnection()) {
+ var rdr = CreateCommand(sql, conn, args).ExecuteReader(CommandBehavior.CloseConnection);
+ while (rdr.Read()) {
+ var e = new MassiveExpando();
+ var d = e as IDictionary<string, object>;
+ for (var i = 0; i < rdr.FieldCount; i++)
+ d.Add(rdr.GetName(i), rdr[i]);
+ yield return e;
+ }
+ }
+ }
+ /// <summary>
+ /// Runs a query against the database
+ /// </summary>
+ public IList<dynamic> Fetch(string sql, params object[] args) {
+ return Query(sql, args).ToList<dynamic>();
+ }
+ /// <summary>
+ /// Returns a single result
+ /// </summary>
+ public object Scalar(string sql, params object[] args) {
+ object result;
+ using (var conn = OpenConnection()) {
+ result = CreateCommand(sql, conn, args).ExecuteScalar();
+ }
+ return result;
+ }
+ /// <summary>
+ /// Creates a DBCommand that you can use for loving your database.
+ /// </summary>
+ DbCommand CreateCommand(string sql, DbConnection conn, params object[] args) {
+ var result = _factory.CreateCommand();
+ result.Connection = conn;
+ result.CommandText = sql;
+ if (args.Length > 0)
+ result.AddParams(args);
+ return result;
+ }
+ /// <summary>
+ /// Returns and OpenConnection
+ /// </summary>
+ public DbConnection OpenConnection() {
+ var conn = _factory.CreateConnection();
+ conn.ConnectionString = _connectionString;
+ conn.Open();
+ return conn;
+ }
+ /// <summary>
+ /// Builds a set of Insert and Update commands based on the passed-on objects.
+ /// These objects can be POCOs, Anonymous, NameValueCollections, or Expandos. Objects
+ /// With a PK property (whatever PrimaryKeyField is set to) will be created at UPDATEs
+ /// </summary>
+ public List<DbCommand> BuildCommands(params object[] things) {
+ var commands = new List<DbCommand>();
+ foreach (var item in things) {
+ if (HasPrimaryKey(item)) {
+ commands.Add(CreateUpdateCommand(item, GetPrimaryKey(item)));
+ } else {
+ commands.Add(CreateInsertCommand(item));
+ }
+ }
+
+ return commands;
+ }
+ /// <summary>
+ /// Executes a set of objects as Insert or Update commands based on their property settings, within a transaction.
+ /// These objects can be POCOs, Anonymous, NameValueCollections, or Expandos. Objects
+ /// With a PK property (whatever PrimaryKeyField is set to) will be created at UPDATEs
+ /// </summary>
+ public int Save(params object[] things) {
+ var commands = BuildCommands(things);
+ return Execute(commands);
+ }
+ public int Execute(DbCommand command) {
+ return Execute(new DbCommand[] { command });
+ }
+ /// <summary>
+ /// Executes a series of DBCommands in a transaction
+ /// </summary>
+ public int Execute(IEnumerable<DbCommand> commands) {
+ var result = 0;
+ using (var conn = OpenConnection())
+ using (var tx = conn.BeginTransaction()) {
+ foreach (var cmd in commands) {
+ cmd.Connection = conn;
+ cmd.Transaction = tx;
+ result += cmd.ExecuteNonQuery();
+ }
+ tx.Commit();
+ }
+ return result;
+ }
+ public string PrimaryKeyField { get; set; }
+ /// <summary>
+ /// Conventionally introspects the object passed in for a field that
+ /// looks like a PK. If you've named your PrimaryKeyField, this becomes easy
+ /// </summary>
+ public bool HasPrimaryKey(object o) {
+ return o.ToDictionary().ContainsKey(PrimaryKeyField);
+ }
+ /// <summary>
+ /// If the object passed in has a property with the same name as your PrimaryKeyField
+ /// it is returned here.
+ /// </summary>
+ public object GetPrimaryKey(object o) {
+ object result;
+ o.ToDictionary().TryGetValue(PrimaryKeyField, out result);
+ return result;
+ }
+ public string TableName { get; set; }
+ /// <summary>
+ /// Creates a command for use with transactions - internal stuff mostly, but here for you to play with
+ /// </summary>
+ public DbCommand CreateInsertCommand(object o) {
+ var expando = o.ToExpando();
+ var settings = (IDictionary<string, object>)expando;
+ var sbKeys = new StringBuilder();
+ var sbVals = new StringBuilder();
+ const string stub = "INSERT INTO {0} ({1}) \r\n VALUES ({2}); \r\nSELECT SCOPE_IDENTITY() as newID;";
+ var result = CreateCommand(stub,null);
+ var counter = 0;
+ foreach (var item in settings) {
+ sbKeys.AppendFormat("{0},", item.Key);
+ sbVals.AppendFormat("@{0},", counter);
+ result.AddParam(item.Value);
+ counter++;
+ }
+ if (counter > 0) {
+ var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 1);
+ var vals = sbVals.ToString().Substring(0, sbVals.Length - 1);
+ var sql = string.Format(stub, TableName, keys, vals);
+ result.CommandText = sql;
+ } else throw new InvalidOperationException("Can't parse this object to the database - there are no properties set");
+ return result;
+ }
+ /// <summary>
+ /// Creates a command for use with transactions - internal stuff mostly, but here for you to play with
+ /// </summary>
+ public DbCommand CreateUpdateCommand(object o, object key) {
+ var expando = o.ToExpando();
+ var settings = (IDictionary<string, object>)expando;
+ var sbKeys = new StringBuilder();
+ var stub = "UPDATE {0} SET {1} WHERE {2} = @{3}";
+ var result = CreateCommand(stub,null);
+ var counter = 0;
+ foreach (var item in settings) {
+ var val = item.Value;
+ if (!item.Key.Equals(PrimaryKeyField, StringComparison.CurrentCultureIgnoreCase) && item.Value != null) {
+ result.AddParam(val);
+ sbKeys.AppendFormat("{0} = @{1}, \r\n", item.Key, counter);
+ counter++;
+ }
+ }
+ if (counter > 0) {
+ //add the key
+ result.AddParam(key);
+ //strip the last commas
+ var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 4);
+ result.CommandText = string.Format(stub, TableName, keys, PrimaryKeyField, counter);
+ } else throw new InvalidOperationException("No parsable object was sent in - could not divine any name/value pairs");
+ return result;
+ }
+ /// <summary>
+ /// Removes one or more records from the DB according to the passed-in WHERE
+ /// </summary>
+ public DbCommand CreateDeleteCommand(string where = "", object key = null, params object[] args) {
+ var sql = string.Format("DELETE FROM {0} ", TableName);
+ if (key != null) {
+ sql += string.Format("WHERE {0}=@0", PrimaryKeyField);
+ args = new object[]{key};
+ } else if (!string.IsNullOrEmpty(where)) {
+ sql += where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase) ? where : "WHERE " + where;
+ }
+ return CreateCommand(sql, null, args);
+ }
+ /// <summary>
+ /// Adds a record to the database. You can pass in an Anonymous object, an MassiveExpando,
+ /// A regular old POCO, or a NameValueColletion from a Request.Form or Request.QueryString
+ /// </summary>
+ public object Insert(object o) {
+ return Execute(CreateInsertCommand(o));
+ }
+ /// <summary>
+ /// Updates a record in the database. You can pass in an Anonymous object, an MassiveExpando,
+ /// A regular old POCO, or a NameValueCollection from a Request.Form or Request.QueryString
+ /// </summary>
+ public int Update(object o, object key) {
+ return Execute(CreateUpdateCommand(o, key));
+ }
+ /// <summary>
+ /// Removes one or more records from the DB according to the passed-in WHERE
+ /// </summary>
+ public int Delete(object key = null, string where = "", params object[] args) {
+ return Execute(CreateDeleteCommand(where: where, key:key, args: args));
+ }
+ /// <summary>
+ /// Returns all records complying with the passed-in WHERE clause and arguments,
+ /// ordered as specified, limited (TOP) by limit.
+ /// </summary>
+ public IEnumerable<dynamic> All(string where = "", string orderBy = "", int limit = 0, string columns = "*", params object[] args) {
+ var sql = limit > 0 ? "SELECT TOP {2} {0} FROM {1} " : "SELECT {0} FROM {1} ";
+ if (!string.IsNullOrEmpty(where))
+ sql += where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase) ? where : "WHERE " + where;
+ if (!String.IsNullOrEmpty(orderBy))
+ sql += orderBy.Trim().StartsWith("order by", StringComparison.CurrentCultureIgnoreCase) ? orderBy : " ORDER BY " + orderBy;
+ return Query(string.Format(sql, columns, TableName, limit), args);
+ }
+
+ /// <summary>
+ /// Returns a dynamic PagedResult. Result properties are Items, TotalPages, and TotalRecords.
+ /// </summary>
+ public dynamic Paged(string where = "", string orderBy = "", string columns = "*", int pageSize = 20, int currentPage =1, params object[] args) {
+ dynamic result = new MassiveExpando();
+ var countSQL = string.Format("SELECT COUNT({0}) FROM {1}", PrimaryKeyField, TableName);
+ if (String.IsNullOrEmpty(orderBy))
+ orderBy = PrimaryKeyField;
+ var sql = string.Format("SELECT {0} FROM (SELECT ROW_NUMBER() OVER (ORDER BY {2}) AS Row, {0} FROM {3}) AS Paged ", columns, pageSize, orderBy, TableName);
+ var pageStart = (currentPage -1) * pageSize;
+ sql+= string.Format(" WHERE Row >= {0} AND Row <= {1}",pageStart, (pageStart + pageSize));
+ var pagedWhere = "";
+ if (!string.IsNullOrEmpty(where)) {
+ if (where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase)) {
+ pagedWhere = Regex.Replace(where, "where ", "and ", RegexOptions.IgnoreCase);
+ }
+ }
+ sql += pagedWhere;
+ countSQL += where;
+ result.TotalRecords = Scalar(countSQL, args);
+ result.TotalPages = result.TotalRecords / pageSize;
+ if (result.TotalRecords % pageSize > 0)
+ result.TotalPages += 1;
+ result.Items = Query(string.Format(sql, columns, TableName), args);
+ return result;
+ }
+ /// <summary>
+ /// Returns a single row from the database
+ /// </summary>
+ public dynamic Single(object key, string columns = "*") {
+ var sql = string.Format("SELECT {0} FROM {1} WHERE {2} = @0", columns, TableName, PrimaryKeyField);
+ return Fetch(sql, key).FirstOrDefault();
+ }
+ }
+
+ public class MassiveExpando : DynamicObject, IDictionary<string, object> {
+ private IDictionary<string, object> Dictionary = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
+
+ public void Add(KeyValuePair<string, object> item) {
+ Dictionary.Add(item);
+ }
+ public void Clear() {
+ Dictionary.Clear();
+ }
+ public bool Contains(KeyValuePair<string, object> item) {
+ return Dictionary.Contains(item);
+ }
+ public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex) {
+ Dictionary.CopyTo(array, arrayIndex);
+ }
+ public bool Remove(KeyValuePair<string, object> item) {
+ return Dictionary.Remove(item);
+ }
+ public int Count { get { return this.Dictionary.Keys.Count; } }
+ public bool IsReadOnly { get { return Dictionary.IsReadOnly; } }
+ public override bool TryGetMember(GetMemberBinder binder, out object result) {
+ if (this.Dictionary.ContainsKey(binder.Name))
+ {
+ result = this.Dictionary[binder.Name];
+ return true;
+ }
+ return base.TryGetMember(binder, out result);
+ }
+ public override bool TrySetMember(SetMemberBinder binder, object value) {
+ if (!this.Dictionary.ContainsKey(binder.Name))
+ this.Dictionary.Add(binder.Name, value);
+ else
+ this.Dictionary[binder.Name] = value;
+ return true;
+ }
+ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
+ if (this.Dictionary.ContainsKey(binder.Name) && this.Dictionary[binder.Name] is Delegate)
+ {
+ Delegate del = this.Dictionary[binder.Name] as Delegate;
+ result = del.DynamicInvoke(args);
+ return true;
+ }
+ return base.TryInvokeMember(binder, args, out result);
+ }
+ public override bool TryDeleteMember(DeleteMemberBinder binder) {
+ if (this.Dictionary.ContainsKey(binder.Name))
+ {
+ this.Dictionary.Remove(binder.Name);
+ return true;
+ }
+ return base.TryDeleteMember(binder);
+ }
+ public IEnumerator<KeyValuePair<string, object>> GetEnumerator() {
+ return Dictionary.GetEnumerator();
+ }
+ IEnumerator IEnumerable.GetEnumerator() {
+ return GetEnumerator();
+ }
+ public bool ContainsKey(string key) {
+ return Dictionary.ContainsKey(key);
+ }
+ public void Add(string key, object value) {
+ Dictionary.Add(key, value);
+ }
+ public bool Remove(string key) {
+ return Dictionary.Remove(key);
+ }
+ public bool TryGetValue(string key, out object value) {
+ return Dictionary.TryGetValue(key, out value);
+ }
+ public object this[string key] {
+ get { return Dictionary[key]; }
+ set { Dictionary[key] = value; }
+ }
+ public ICollection<string> Keys {
+ get { return Dictionary.Keys; }
+ }
+ public ICollection<object> Values {
+ get { return Dictionary.Values; }
+ }
+ }
}
View
2  README.markdown
@@ -4,7 +4,7 @@ Massive is a Single File Database Lover. Move over Bacon - Taste is got a new fr
I'm sharing this with the world because we need another way to access data - don't you think? Truthfully - I wanted to see if I could flex the C# 4 stuff and
run up data access with a single file. I used to have this down to 350 lines, but you also needed to reference WebMatrix.Data. Now you don't - this is ready to roll
-and weighs in at a lovely 524 lines of code. Most of which is comments.
+and weighs in at a lovely 352 lines of code. Most of which is comments.
How To Install It?
------------------
Something went wrong with that request. Please try again.