Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

ReSharper and GhostDoc cleanup. #15

Closed
wants to merge 2 commits into from

2 participants

Bill Forney Rob Conery
Bill Forney

Did a bit of ReSharper and GhostDoc cleanup.

Rob Conery
Owner

I'd love to take this pull but I can't tell what's changed - the diff is a massive green block and a massive red block.

Bill Forney

Oh, there isn't much. I used GhostDoc to add some comments and then ReSharper to reformat the code. I pulled the one class out into another file (which you could just stuff back in there if you want). Other than that, I don't think it really did too much. I'll run a diff with Beyond Compare and see if I can provide detail to any actual changes that aren't comments.

Bill Forney

Ok, so aside from adding comments, redundant usings, and reformatting these things changed...

            var d = e as IDictionary<string, object>;
            for (int i = 0; i < rdr.FieldCount; i++)

changed to this:

            var d = (IDictionary<string, object>)e;
            for (var i = 0; i < rdr.FieldCount; i++)

this line:

            nv.Cast<string>().Select(key => new KeyValuePair<string, object>(key, nv[key])).ToList().ForEach(i => d.Add(i));

changed to this:

            nv.Cast<string>().Select(key => new KeyValuePair<string, object>(key, nv[key])).ToList().ForEach(d.Add);

Then the DynamicModel.cs was added and class moved into it and these changed...

            throw new InvalidOperationException("Can't find a connection string with the name '" + connectionStringName + "'");

becomes this:

            throw new InvalidOperationException(string.Format("Can't find a connection string with the name '{0}'", connectionStringName));

A few lines had redundant assignments to null that were removed.

        var stub = "INSERT INTO {0} ({1}) \r\n VALUES ({2})";

became:

        const string Stub = "INSERT INTO {0} ({1}) \r\n VALUES ({2})";

A few other lines like that were in other methods as well.

        var sql = string.Format("SELECT {0} FROM (SELECT ROW_NUMBER() OVER (ORDER BY {2}) AS Row, {0} FROM {3} {4}) AS Paged ",columns,pageSize,orderBy,TableName, where);

was swapped with this:

        var sql =
            string.Format(
                "SELECT {0} FROM (SELECT ROW_NUMBER() OVER (ORDER BY {1}) AS Row, {0} FROM {2} {3}) AS Paged ",
                columns,
                orderBy,
                this.TableName,
                where);

and this was changed in this method...

    DbCommand CreateCommand(string sql, DbConnection conn, params object[] args) {
        DbCommand result = null;
        result = _factory.CreateCommand();

to...

    private DbCommand CreateCommand(string sql, DbConnection conn, params object[] args)
    {
        var result = this._factory.CreateCommand();
        if (result == null)
        {
            throw new NullReferenceException("The command should not be null.");
        }

That should cover all the relevant changes.

Bill Forney

Oh, make sure you get the version with my latest edit tonight as ReSharper swapped dynamic for object in a few spots and I had to go back and fix it.

Rob Conery
Owner

As much as I appreciate what you've done - I like the way the code is laid out, and I like my comments as well.

Bill Forney

Ok, no big :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 2 unique commits by 1 author.

Mar 02, 2011
Bill Forney wforney ReSharper and GhostDoc cleanup. 0d2f970
Mar 08, 2011
Bill Forney wforney ReSharper has a bad habit of swapping dynamic for object in places. T…
…his fixes that.
917f27a
This page is out of date. Refresh to see the latest.

Showing 2 changed files with 628 additions and 313 deletions. Show diff stats Hide diff stats

  1. +532 0 DynamicModel.cs
  2. +96 313 Massive.cs
532 DynamicModel.cs
... ... @@ -0,0 +1,532 @@
  1 +// --------------------------------------------------------------------------------------------------------------------
  2 +// <copyright file="DynamicModel.cs" company="">
  3 +//
  4 +// </copyright>
  5 +// <summary>
  6 +// A class that wraps your database table in Dynamic Fun-time
  7 +// </summary>
  8 +// --------------------------------------------------------------------------------------------------------------------
  9 +
  10 +namespace Massive
  11 +{
  12 + using System;
  13 + using System.Collections.Generic;
  14 + using System.Configuration;
  15 + using System.Data;
  16 + using System.Data.Common;
  17 + using System.Diagnostics.Contracts;
  18 + using System.Dynamic;
  19 + using System.Linq;
  20 + using System.Text;
  21 +
  22 + /// <summary>
  23 + /// A class that wraps your database table in Dynamic Fun-time
  24 + /// </summary>
  25 + /// <remarks></remarks>
  26 + public class DynamicModel
  27 + {
  28 + /// <summary>
  29 + /// The factory.
  30 + /// </summary>
  31 + private readonly DbProviderFactory _factory;
  32 +
  33 + /// <summary>
  34 + /// The connection string.
  35 + /// </summary>
  36 + private readonly string _connectionString;
  37 +
  38 + /// <summary>
  39 + /// Initializes a new instance of the <see cref="DynamicModel"/> class.
  40 + /// </summary>
  41 + /// <param name="connectionStringName">Name of the connection string.</param>
  42 + /// <param name="tableName">Name of the table.</param>
  43 + /// <param name="primaryKeyField">The primary key field.</param>
  44 + /// <remarks></remarks>
  45 + public DynamicModel(string connectionStringName = "", string tableName = "", string primaryKeyField = "")
  46 + {
  47 + this.TableName = tableName == "" ? this.GetType().Name : tableName;
  48 + this.PrimaryKeyField = string.IsNullOrEmpty(primaryKeyField) ? "ID" : primaryKeyField;
  49 +
  50 + if (connectionStringName == "")
  51 + {
  52 + connectionStringName = ConfigurationManager.ConnectionStrings[0].Name;
  53 + }
  54 +
  55 + var providerName = "System.Data.SqlClient";
  56 + if (ConfigurationManager.ConnectionStrings[connectionStringName] != null)
  57 + {
  58 + if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName))
  59 + {
  60 + providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;
  61 + }
  62 + }
  63 + else
  64 + {
  65 + throw new InvalidOperationException(string.Format("Can't find a connection string with the name '{0}'", connectionStringName));
  66 + }
  67 +
  68 + this._factory = DbProviderFactories.GetFactory(providerName);
  69 + this._connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
  70 + }
  71 +
  72 + /// <summary>
  73 + /// Gets or sets the primary key field.
  74 + /// </summary>
  75 + /// <value>The primary key field.</value>
  76 + /// <remarks></remarks>
  77 + public string PrimaryKeyField { get; set; }
  78 +
  79 + /// <summary>
  80 + /// Gets or sets the name of the table.
  81 + /// </summary>
  82 + /// <value>The name of the table.</value>
  83 + /// <remarks></remarks>
  84 + public string TableName { get; set; }
  85 +
  86 + /// <summary>
  87 + /// Enumerates the reader yielding the result - thanks to Jeroen Haegebaert
  88 + /// </summary>
  89 + /// <param name="sql">The SQL.</param>
  90 + /// <param name="args">The arguments.</param>
  91 + /// <returns>An enumerable interface of dynamic objects.</returns>
  92 + /// <remarks></remarks>
  93 + public IEnumerable<dynamic> Query(string sql, params object[] args)
  94 + {
  95 + using (var conn = this.OpenConnection())
  96 + {
  97 + var rdr = this.CreateCommand(sql, conn, args).ExecuteReader(CommandBehavior.CloseConnection);
  98 + while (rdr.Read())
  99 + {
  100 + var e = new ExpandoObject();
  101 + var d = e as IDictionary<string, object>;
  102 + for (var i = 0; i < rdr.FieldCount; i++)
  103 + {
  104 + d.Add(rdr.GetName(i), rdr[i]);
  105 + }
  106 +
  107 + yield return e;
  108 + }
  109 + }
  110 + }
  111 +
  112 + /// <summary>
  113 + /// Runs a query against the database
  114 + /// </summary>
  115 + /// <param name="sql">The SQL.</param>
  116 + /// <param name="args">The arguments.</param>
  117 + /// <returns>A list interface of dynamic objects.</returns>
  118 + /// <remarks></remarks>
  119 + public IList<dynamic> Fetch(string sql, params object[] args)
  120 + {
  121 + return this.Query(sql, args).ToList<dynamic>();
  122 + }
  123 +
  124 + /// <summary>
  125 + /// Returns a single result
  126 + /// </summary>
  127 + /// <param name="sql">The SQL.</param>
  128 + /// <param name="args">The arguments.</param>
  129 + /// <returns>The result.</returns>
  130 + /// <remarks></remarks>
  131 + public object Scalar(string sql, params object[] args)
  132 + {
  133 + object result;
  134 + using (var conn = this.OpenConnection())
  135 + {
  136 + result = this.CreateCommand(sql, conn, args).ExecuteScalar();
  137 + }
  138 +
  139 + return result;
  140 + }
  141 +
  142 + /// <summary>
  143 + /// Returns an open connection.
  144 + /// </summary>
  145 + /// <returns>A connection.</returns>
  146 + /// <remarks></remarks>
  147 + public DbConnection OpenConnection()
  148 + {
  149 + var conn = this._factory.CreateConnection();
  150 + if (conn == null)
  151 + {
  152 + throw new NullReferenceException("The connection should not be null.");
  153 + }
  154 +
  155 + conn.ConnectionString = this._connectionString;
  156 + conn.Open();
  157 + return conn;
  158 + }
  159 +
  160 + /// <summary>
  161 + /// Builds a set of Insert and Update commands based on the passed-on objects.
  162 + /// These objects can be POCOs, Anonymous, NameValueCollections, or Expandos. Objects
  163 + /// With a PK property (whatever PrimaryKeyField is set to) will be created at UPDATEs
  164 + /// </summary>
  165 + /// <param name="things">The things.</param>
  166 + /// <returns>A list of commands.</returns>
  167 + /// <remarks></remarks>
  168 + public List<DbCommand> BuildCommands(params object[] things)
  169 + {
  170 + Contract.Requires(things != null);
  171 + return
  172 + things.Select(
  173 + item =>
  174 + this.HasPrimaryKey(item)
  175 + ? this.CreateUpdateCommand(item, this.GetPrimaryKey(item))
  176 + : this.CreateInsertCommand(item)).ToList();
  177 + }
  178 +
  179 + /// <summary>
  180 + /// Executes a set of objects as Insert or Update commands based on their property settings, within a transaction.
  181 + /// These objects can be POCOs, Anonymous, NameValueCollections, or Expandos. Objects
  182 + /// With a PK property (whatever PrimaryKeyField is set to) will be created at UPDATEs
  183 + /// </summary>
  184 + /// <param name="things">The things.</param>
  185 + /// <returns>An integer.</returns>
  186 + /// <remarks></remarks>
  187 + public int Save(params object[] things)
  188 + {
  189 + Contract.Requires(things != null);
  190 + var commands = this.BuildCommands(things);
  191 + return this.Execute(commands);
  192 + }
  193 +
  194 + /// <summary>
  195 + /// Executes the specified command.
  196 + /// </summary>
  197 + /// <param name="command">The command.</param>
  198 + /// <returns>An integer.</returns>
  199 + /// <remarks></remarks>
  200 + public int Execute(DbCommand command)
  201 + {
  202 + return this.Execute(new[] { command });
  203 + }
  204 +
  205 + /// <summary>
  206 + /// Executes a series of DBCommands in a transaction
  207 + /// </summary>
  208 + /// <param name="commands">The commands.</param>
  209 + /// <returns>An integer.</returns>
  210 + /// <remarks></remarks>
  211 + public int Execute(IEnumerable<DbCommand> commands)
  212 + {
  213 + var result = 0;
  214 + using (var conn = this.OpenConnection())
  215 + using (var tx = conn.BeginTransaction())
  216 + {
  217 + foreach (var cmd in commands)
  218 + {
  219 + cmd.Connection = conn;
  220 + cmd.Transaction = tx;
  221 + result += cmd.ExecuteNonQuery();
  222 + }
  223 +
  224 + tx.Commit();
  225 + }
  226 +
  227 + return result;
  228 + }
  229 +
  230 + /// <summary>
  231 + /// Conventionally introspects the object passed in for a field that
  232 + /// looks like a PK. If you've named your PrimaryKeyField, this becomes easy
  233 + /// </summary>
  234 + /// <param name="o">The o.</param>
  235 + /// <returns><c>true</c> if [has primary key] [the specified o]; otherwise, <c>false</c>.</returns>
  236 + /// <remarks></remarks>
  237 + public bool HasPrimaryKey(object o)
  238 + {
  239 + return o.ToDictionary().ContainsKey(this.PrimaryKeyField);
  240 + }
  241 +
  242 + /// <summary>
  243 + /// If the object passed in has a property with the same name as your PrimaryKeyField
  244 + /// it is returned here.
  245 + /// </summary>
  246 + /// <param name="o">The o.</param>
  247 + /// <returns>The primary key.</returns>
  248 + /// <remarks></remarks>
  249 + public object GetPrimaryKey(object o)
  250 + {
  251 + object result;
  252 + o.ToDictionary().TryGetValue(this.PrimaryKeyField, out result);
  253 + return result;
  254 + }
  255 +
  256 + /// <summary>
  257 + /// Creates a command for use with transactions - internal stuff mostly, but here for you to play with
  258 + /// </summary>
  259 + /// <param name="o">The o.</param>
  260 + /// <returns>The insert command.</returns>
  261 + /// <remarks></remarks>
  262 + public DbCommand CreateInsertCommand(object o)
  263 + {
  264 + var expando = o.ToExpando();
  265 + var settings = (IDictionary<string, object>)expando;
  266 + var sbKeys = new StringBuilder();
  267 + var sbVals = new StringBuilder();
  268 + const string Stub = "INSERT INTO {0} ({1}) \r\n VALUES ({2})";
  269 + var result = this.CreateCommand(Stub, null);
  270 + var counter = 0;
  271 + foreach (var item in settings)
  272 + {
  273 + sbKeys.AppendFormat("{0},", item.Key);
  274 + sbVals.AppendFormat("@{0},", counter);
  275 + result.AddParam(item.Value);
  276 + counter++;
  277 + }
  278 +
  279 + if (counter > 0)
  280 + {
  281 + var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 1);
  282 + var vals = sbVals.ToString().Substring(0, sbVals.Length - 1);
  283 + var sql = string.Format(Stub, this.TableName, keys, vals);
  284 + result.CommandText = sql;
  285 + }
  286 + else
  287 + {
  288 + throw new InvalidOperationException(
  289 + "Can't parse this object to the database - there are no properties set");
  290 + }
  291 +
  292 + return result;
  293 + }
  294 +
  295 + /// <summary>
  296 + /// Creates a command for use with transactions - internal stuff mostly, but here for you to play with
  297 + /// </summary>
  298 + /// <param name="o">The o.</param>
  299 + /// <param name="key">The key.</param>
  300 + /// <returns>The update command.</returns>
  301 + /// <remarks></remarks>
  302 + public DbCommand CreateUpdateCommand(object o, object key)
  303 + {
  304 + var expando = o.ToExpando();
  305 + var settings = (IDictionary<string, object>)expando;
  306 + var sbKeys = new StringBuilder();
  307 + const string Stub = "UPDATE {0} SET {1} WHERE {2} = @{3}";
  308 + var result = this.CreateCommand(Stub, null);
  309 + var counter = 0;
  310 + foreach (var item in settings)
  311 + {
  312 + var val = item.Value;
  313 + if (item.Key.Equals(this.PrimaryKeyField, StringComparison.CurrentCultureIgnoreCase) ||
  314 + item.Value == null)
  315 + {
  316 + continue;
  317 + }
  318 +
  319 + result.AddParam(val);
  320 + sbKeys.AppendFormat("{0} = @{1}, \r\n", item.Key, counter);
  321 + counter++;
  322 + }
  323 +
  324 + if (counter > 0)
  325 + {
  326 + // add the key
  327 + result.AddParam(key);
  328 +
  329 + // strip the last commas
  330 + var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 4);
  331 + result.CommandText = string.Format(Stub, this.TableName, keys, this.PrimaryKeyField, counter);
  332 + }
  333 + else
  334 + {
  335 + throw new InvalidOperationException("No parsable object was sent in - could not divine any name/value pairs");
  336 + }
  337 +
  338 + return result;
  339 + }
  340 +
  341 + /// <summary>
  342 + /// Removes one or more records from the DB according to the passed-in WHERE
  343 + /// </summary>
  344 + /// <param name="where">The where.</param>
  345 + /// <param name="key">The key.</param>
  346 + /// <param name="args">The arguments.</param>
  347 + /// <returns>A delete command.</returns>
  348 + /// <remarks></remarks>
  349 + public DbCommand CreateDeleteCommand(string where = "", object key = null, params object[] args)
  350 + {
  351 + var sql = string.Format("DELETE FROM {0} ", this.TableName);
  352 + if (key != null)
  353 + {
  354 + sql += string.Format("WHERE {0}=@0", this.PrimaryKeyField);
  355 + args = new[] { key };
  356 + }
  357 + else if (!string.IsNullOrEmpty(where))
  358 + {
  359 + sql += where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase) ? where : "WHERE " + where;
  360 + }
  361 +
  362 + return this.CreateCommand(sql, null, args);
  363 + }
  364 +
  365 + /// <summary>
  366 + /// Adds a record to the database. You can pass in an Anonymous object, an ExpandoObject,
  367 + /// A regular old POCO, or a NameValueColletion from a Request.Form or Request.QueryString
  368 + /// </summary>
  369 + /// <param name="o">The o.</param>
  370 + /// <returns>The result.</returns>
  371 + /// <remarks></remarks>
  372 + public object Insert(object o)
  373 + {
  374 + dynamic result;
  375 + using (var conn = this.OpenConnection())
  376 + {
  377 + var cmd = this.CreateInsertCommand(o);
  378 + cmd.Connection = conn;
  379 + cmd.ExecuteNonQuery();
  380 + cmd.CommandText = "SELECT @@IDENTITY as newID";
  381 + result = cmd.ExecuteScalar();
  382 + }
  383 +
  384 + return result;
  385 + }
  386 +
  387 + /// <summary>
  388 + /// Updates a record in the database. You can pass in an Anonymous object, an ExpandoObject,
  389 + /// A regular old POCO, or a NameValueCollection from a Request.Form or Request.QueryString
  390 + /// </summary>
  391 + /// <param name="o">The o.</param>
  392 + /// <param name="key">The key.</param>
  393 + /// <returns>The result.</returns>
  394 + /// <remarks></remarks>
  395 + public int Update(object o, object key)
  396 + {
  397 + return this.Execute(this.CreateUpdateCommand(o, key));
  398 + }
  399 +
  400 + /// <summary>
  401 + /// Removes one or more records from the DB according to the passed-in WHERE
  402 + /// </summary>
  403 + /// <param name="key">The key.</param>
  404 + /// <param name="where">The where.</param>
  405 + /// <param name="args">The arguments.</param>
  406 + /// <returns>The result.</returns>
  407 + /// <remarks></remarks>
  408 + public int Delete(object key = null, string where = "", params object[] args)
  409 + {
  410 + return this.Execute(this.CreateDeleteCommand(where, key, args));
  411 + }
  412 +
  413 + /// <summary>
  414 + /// Returns all records complying with the passed-in WHERE clause and arguments,
  415 + /// ordered as specified, limited (TOP) by limit.
  416 + /// </summary>
  417 + /// <param name="where">The where.</param>
  418 + /// <param name="orderBy">The order by.</param>
  419 + /// <param name="limit">The limit.</param>
  420 + /// <param name="columns">The columns.</param>
  421 + /// <param name="args">The arguments.</param>
  422 + /// <returns>An enumerable interface of dynamic.</returns>
  423 + /// <remarks></remarks>
  424 + public IEnumerable<object> All(string where = "", string orderBy = "", int limit = 0, string columns = "*", params object[] args)
  425 + {
  426 + var sql = limit > 0 ? "SELECT TOP " + limit + " {0} FROM {1} " : "SELECT {0} FROM {1} ";
  427 + if (!string.IsNullOrEmpty(where))
  428 + {
  429 + sql += where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase)
  430 + ? where
  431 + : "WHERE " + where;
  432 + }
  433 +
  434 + if (!String.IsNullOrEmpty(orderBy))
  435 + {
  436 + sql += orderBy.Trim().StartsWith("order by", StringComparison.CurrentCultureIgnoreCase)
  437 + ? orderBy
  438 + : " ORDER BY " + orderBy;
  439 + }
  440 +
  441 + return this.Query(string.Format(sql, columns, this.TableName), args);
  442 + }
  443 +
  444 + /// <summary>
  445 + /// Returns a dynamic PagedResult. Result properties are Items, TotalPages, and TotalRecords.
  446 + /// </summary>
  447 + /// <param name="where">The where.</param>
  448 + /// <param name="orderBy">The order by.</param>
  449 + /// <param name="columns">The columns.</param>
  450 + /// <param name="pageSize">Size of the page.</param>
  451 + /// <param name="currentPage">The current page.</param>
  452 + /// <param name="args">The arguments.</param>
  453 + /// <returns>The result.</returns>
  454 + /// <remarks></remarks>
  455 + public dynamic Paged(string where = "", string orderBy = "", string columns = "*", int pageSize = 20, int currentPage = 1, params object[] args)
  456 + {
  457 + dynamic result = new ExpandoObject();
  458 + var countSQL = string.Format("SELECT COUNT({0}) FROM {1}", this.PrimaryKeyField, this.TableName);
  459 + if (String.IsNullOrEmpty(orderBy))
  460 + {
  461 + orderBy = this.PrimaryKeyField;
  462 + }
  463 +
  464 + if (!string.IsNullOrEmpty(where))
  465 + {
  466 + if (!where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase))
  467 + {
  468 + where = "WHERE " + where;
  469 + }
  470 + }
  471 +
  472 + var sql =
  473 + string.Format(
  474 + "SELECT {0} FROM (SELECT ROW_NUMBER() OVER (ORDER BY {1}) AS Row, {0} FROM {2} {3}) AS Paged ",
  475 + columns,
  476 + orderBy,
  477 + this.TableName,
  478 + where);
  479 + var pageStart = (currentPage - 1) * pageSize;
  480 + sql += string.Format(" WHERE Row >={0} AND Row <={1}", pageStart, (pageStart + pageSize));
  481 + countSQL += where;
  482 + result.TotalRecords = this.Scalar(countSQL, args);
  483 + result.TotalPages = result.TotalRecords / pageSize;
  484 + if (result.TotalRecords % pageSize > 0)
  485 + {
  486 + result.TotalPages += 1;
  487 + }
  488 +
  489 + result.Items = this.Query(string.Format(sql, columns, this.TableName), args);
  490 + return result;
  491 + }
  492 +
  493 + /// <summary>
  494 + /// Returns a single row from the database
  495 + /// </summary>
  496 + /// <param name="key">The key.</param>
  497 + /// <param name="columns">The columns.</param>
  498 + /// <returns>The row.</returns>
  499 + /// <remarks></remarks>
  500 + public dynamic Single(object key, string columns = "*")
  501 + {
  502 + var sql = string.Format("SELECT {0} FROM {1} WHERE {2} = @0", columns, this.TableName, this.PrimaryKeyField);
  503 + return this.Fetch(sql, key).FirstOrDefault();
  504 + }
  505 +
  506 + /// <summary>
  507 + /// Creates a DBCommand that you can use for loving your database.
  508 + /// </summary>
  509 + /// <param name="sql">The SQL.</param>
  510 + /// <param name="conn">The connection.</param>
  511 + /// <param name="args">The arguments.</param>
  512 + /// <returns>A command.</returns>
  513 + /// <remarks></remarks>
  514 + private DbCommand CreateCommand(string sql, DbConnection conn, params object[] args)
  515 + {
  516 + var result = this._factory.CreateCommand();
  517 + if (result == null)
  518 + {
  519 + throw new NullReferenceException("The command should not be null.");
  520 + }
  521 +
  522 + result.Connection = conn;
  523 + result.CommandText = sql;
  524 + if (args.Length > 0)
  525 + {
  526 + result.AddParams(args);
  527 + }
  528 +
  529 + return result;
  530 + }
  531 + }
  532 +}
409 Massive.cs
... ... @@ -1,366 +1,149 @@
1   -using System;
2   -using System.Collections.Generic;
3   -using System.Collections.Specialized;
4   -using System.Configuration;
5   -using System.Data;
6   -using System.Data.Common;
7   -using System.Dynamic;
8   -using System.Linq;
9   -using System.Text;
10   -using System.Collections;
11   -using System.Text.RegularExpressions;
  1 +// --------------------------------------------------------------------------------------------------------------------
  2 +// <copyright file="Massive.cs" company="">
  3 +//
  4 +// </copyright>
  5 +// <summary>
  6 +// Defines the ObjectExtensions type.
  7 +// </summary>
  8 +// --------------------------------------------------------------------------------------------------------------------
12 9
13   -namespace Massive {
14   - public static class ObjectExtensions {
  10 +namespace Massive
  11 +{
  12 + using System;
  13 + using System.Collections.Generic;
  14 + using System.Collections.Specialized;
  15 + using System.Data;
  16 + using System.Data.Common;
  17 + using System.Dynamic;
  18 + using System.Linq;
  19 +
  20 + /// <summary>
  21 + /// Object Extensions
  22 + /// </summary>
  23 + /// <remarks></remarks>
  24 + public static class ObjectExtensions
  25 + {
15 26 /// <summary>
16 27 /// Extension method for adding in a bunch of parameters
17 28 /// </summary>
18   - public static void AddParams(this DbCommand cmd, object[] args) {
19   - foreach (var item in args) {
  29 + /// <param name="cmd">The command.</param>
  30 + /// <param name="args">The arguments.</param>
  31 + /// <remarks></remarks>
  32 + public static void AddParams(this DbCommand cmd, object[] args)
  33 + {
  34 + foreach (var item in args)
  35 + {
20 36 AddParam(cmd, item);
21 37 }
22 38 }
  39 +
23 40 /// <summary>
24 41 /// Extension for adding single parameter
25 42 /// </summary>
26   - public static void AddParam(this DbCommand cmd, object item) {
  43 + /// <param name="cmd">The CMD.</param>
  44 + /// <param name="item">The item.</param>
  45 + /// <remarks></remarks>
  46 + public static void AddParam(this DbCommand cmd, object item)
  47 + {
27 48 var p = cmd.CreateParameter();
28 49 p.ParameterName = string.Format("@{0}", cmd.Parameters.Count);
29   - if (item == null) {
  50 + if (item == null)
  51 + {
30 52 p.Value = DBNull.Value;
31   - } else {
32   - if (item.GetType() == typeof(Guid)) {
  53 + }
  54 + else
  55 + {
  56 + if (item.GetType() == typeof(Guid))
  57 + {
33 58 p.Value = item.ToString();
34 59 p.DbType = DbType.String;
35 60 p.Size = 4000;
36   - }else if(item.GetType()==typeof(ExpandoObject)){
  61 + }
  62 + else if (item.GetType() == typeof(ExpandoObject))
  63 + {
37 64 var d = (IDictionary<string, object>)item;
38 65 p.Value = d.Values.FirstOrDefault();
39   - } else {
  66 + }
  67 + else
  68 + {
40 69 p.Value = item;
41 70 }
42   - //from DataChomp
  71 +
  72 + // from DataChomp
43 73 if (item.GetType() == typeof(string))
  74 + {
44 75 p.Size = 4000;
  76 + }
45 77 }
  78 +
46 79 cmd.Parameters.Add(p);
47 80 }
  81 +
48 82 /// <summary>
49 83 /// Turns an IDataReader to a Dynamic list of things
50 84 /// </summary>
51   - public static List<dynamic> ToExpandoList(this IDataReader rdr) {
  85 + /// <param name="rdr">The reader.</param>
  86 + /// <returns>A list of dynamic things.</returns>
  87 + /// <remarks></remarks>
  88 + public static List<dynamic> ToExpandoList(this IDataReader rdr)
  89 + {
52 90 var result = new List<dynamic>();
53   - while (rdr.Read()) {
  91 + while (rdr.Read())
  92 + {
54 93 dynamic e = new ExpandoObject();
55   - var d = e as IDictionary<string, object>;
56   - for (int i = 0; i < rdr.FieldCount; i++)
  94 + var d = (IDictionary<string, object>)e;
  95 + for (var i = 0; i < rdr.FieldCount; i++)
  96 + {
57 97 d.Add(rdr.GetName(i), rdr[i]);
  98 + }
  99 +
58 100 result.Add(e);
59 101 }
  102 +
60 103 return result;
61 104 }
  105 +
62 106 /// <summary>
63 107 /// Turns the object into an ExpandoObject
64 108 /// </summary>
65   - public static dynamic ToExpando(this object o) {
  109 + /// <param name="o">The o.</param>
  110 + /// <returns>An ExpandoObject.</returns>
  111 + /// <remarks></remarks>
  112 + public static dynamic ToExpando(this object o)
  113 + {
66 114 var result = new ExpandoObject();
67   - var d = result as IDictionary<string, object>; //work with the Expando as a Dictionary
68   - if (o.GetType() == typeof(ExpandoObject)) return o; //shouldn't have to... but just in case
69   - if (o.GetType() == typeof(NameValueCollection)) {
  115 + var d = result as IDictionary<string, object>; // work with the Expando as a Dictionary
  116 + if (o.GetType() == typeof(ExpandoObject))
  117 + {
  118 + return o; // shouldn't have to... but just in case
  119 + }
  120 +
  121 + if (o.GetType() == typeof(NameValueCollection))
  122 + {
70 123 var nv = (NameValueCollection)o;
71   - nv.Cast<string>().Select(key => new KeyValuePair<string, object>(key, nv[key])).ToList().ForEach(i => d.Add(i));
72   - } else {
  124 + nv.Cast<string>().Select(key => new KeyValuePair<string, object>(key, nv[key])).ToList().ForEach(d.Add);
  125 + }
  126 + else
  127 + {
73 128 var props = o.GetType().GetProperties();
74   - foreach (var item in props) {
  129 + foreach (var item in props)
  130 + {
75 131 d.Add(item.Name, item.GetValue(o, null));
76 132 }
77 133 }
78   - return result;
79   - }
80   - /// <summary>
81   - /// Turns the object into a Dictionary
82   - /// </summary>
83   - public static IDictionary<string, object> ToDictionary(this object thingy) {
84   - return (IDictionary<string, object>)thingy.ToExpando();
85   - }
86   - }
87   - /// <summary>
88   - /// A class that wraps your database table in Dynamic Funtime
89   - /// </summary>
90   - public class DynamicModel {
91   - DbProviderFactory _factory;
92   - string _connectionString;
93 134
94   - public DynamicModel(string connectionStringName= "", string tableName = "", string primaryKeyField ="") {
95   - TableName = tableName == "" ? this.GetType().Name : tableName;
96   - PrimaryKeyField = string.IsNullOrEmpty(primaryKeyField) ? "ID" : primaryKeyField;
97   - if (connectionStringName == "")
98   - connectionStringName = ConfigurationManager.ConnectionStrings[0].Name;
99   - var _providerName = "System.Data.SqlClient";
100   - if (ConfigurationManager.ConnectionStrings[connectionStringName] != null) {
101   - if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName))
102   - _providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;
103   - } else {
104   - throw new InvalidOperationException("Can't find a connection string with the name '" + connectionStringName + "'");
105   - }
106   - _factory = DbProviderFactories.GetFactory(_providerName);
107   - _connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
108   - }
109   - /// <summary>
110   - /// Enumerates the reader yielding the result - thanks to Jeroen Haegebaert
111   - /// </summary>
112   - public IEnumerable<dynamic> Query(string sql, params object[] args) {
113   - using (var conn = OpenConnection()) {
114   - var rdr = CreateCommand(sql, conn, args).ExecuteReader(CommandBehavior.CloseConnection);
115   - while (rdr.Read()) {
116   - var e = new ExpandoObject();
117   - var d = e as IDictionary<string, object>;
118   - for (var i = 0; i < rdr.FieldCount; i++)
119   - d.Add(rdr.GetName(i), rdr[i]);
120   - yield return e;
121   - }
122   - }
123   - }
124   - /// <summary>
125   - /// Runs a query against the database
126   - /// </summary>
127   - public IList<dynamic> Fetch(string sql, params object[] args) {
128   - return Query(sql, args).ToList<dynamic>();
129   - }
130   - /// <summary>
131   - /// Returns a single result
132   - /// </summary>
133   - public object Scalar(string sql, params object[] args) {
134   - object result = null;
135   - using (var conn = OpenConnection()) {
136   - result = CreateCommand(sql, conn, args).ExecuteScalar();
137   - }
138   - return result;
139   - }
140   - /// <summary>
141   - /// Creates a DBCommand that you can use for loving your database.
142   - /// </summary>
143   - DbCommand CreateCommand(string sql, DbConnection conn, params object[] args) {
144   - DbCommand result = null;
145   - result = _factory.CreateCommand();
146   - result.Connection = conn;
147   - result.CommandText = sql;
148   - if (args.Length > 0)
149   - result.AddParams(args);
150 135 return result;
151 136 }
152   - /// <summary>
153   - /// Returns and OpenConnection
154   - /// </summary>
155   - public DbConnection OpenConnection() {
156   - var conn = _factory.CreateConnection();
157   - conn.ConnectionString = _connectionString;
158   - conn.Open();
159   - return conn;
160   - }
161   - /// <summary>
162   - /// Builds a set of Insert and Update commands based on the passed-on objects.
163   - /// These objects can be POCOs, Anonymous, NameValueCollections, or Expandos. Objects
164   - /// With a PK property (whatever PrimaryKeyField is set to) will be created at UPDATEs
165   - /// </summary>
166   - public List<DbCommand> BuildCommands(params object[] things) {
167   - var commands = new List<DbCommand>();
168   - foreach (var item in things) {
169   - if (HasPrimaryKey(item)) {
170   - commands.Add(CreateUpdateCommand(item,GetPrimaryKey(item)));
171   - }else{
172   - commands.Add(CreateInsertCommand(item));
173   - }
174   - }
175 137
176   - return commands;
177   - }
178 138 /// <summary>
179   - /// Executes a set of objects as Insert or Update commands based on their property settings, within a transaction.
180   - /// These objects can be POCOs, Anonymous, NameValueCollections, or Expandos. Objects
181   - /// With a PK property (whatever PrimaryKeyField is set to) will be created at UPDATEs
182   - /// </summary>
183   - public int Save(params object[] things) {
184   - var commands = BuildCommands(things);
185   - return Execute(commands);
186   - }
187   - public int Execute(DbCommand command) {
188   - return Execute(new DbCommand[] { command });
189   - }
190   - /// <summary>
191   - /// Executes a series of DBCommands in a transaction
192   - /// </summary>
193   - public int Execute(IEnumerable<DbCommand> commands) {
194   - var result = 0;
195   - using (var conn = OpenConnection()) {
196   - using (var tx = conn.BeginTransaction()) {
197   - foreach (var cmd in commands) {
198   - cmd.Connection = conn;
199   - cmd.Transaction = tx;
200   - result+=cmd.ExecuteNonQuery();
201   - }
202   - tx.Commit();
203   - }
204   - }
205   - return result;
206   - }
207   - public string PrimaryKeyField { get; set; }
208   - /// <summary>
209   - /// Conventionally introspects the object passed in for a field that
210   - /// looks like a PK. If you've named your PrimaryKeyField, this becomes easy
211   - /// </summary>
212   - public bool HasPrimaryKey(object o) {
213   - return o.ToDictionary().ContainsKey(PrimaryKeyField);
214   - }
215   - /// <summary>
216   - /// If the object passed in has a property with the same name as your PrimaryKeyField
217   - /// it is returned here.
218   - /// </summary>
219   - public object GetPrimaryKey(object o) {
220   - object result = null;
221   - o.ToDictionary().TryGetValue(PrimaryKeyField, out result);
222   - return result;
223   - }
224   - public string TableName { get; set; }
225   - /// <summary>
226   - /// Creates a command for use with transactions - internal stuff mostly, but here for you to play with
227   - /// </summary>
228   - public DbCommand CreateInsertCommand(object o) {
229   - DbCommand result = null;
230   - var expando = o.ToExpando();
231   - var settings = (IDictionary<string, object>)expando;
232   - var sbKeys = new StringBuilder();
233   - var sbVals = new StringBuilder();
234   - var stub = "INSERT INTO {0} ({1}) \r\n VALUES ({2})";
235   - result = CreateCommand(stub,null);
236   - int counter = 0;
237   - foreach (var item in settings) {
238   - sbKeys.AppendFormat("{0},", item.Key);
239   - sbVals.AppendFormat("@{0},", counter.ToString());
240   - result.AddParam(item.Value);
241   - counter++;
242   - }
243   - if (counter > 0) {
244   - var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 1);
245   - var vals = sbVals.ToString().Substring(0, sbVals.Length - 1);
246   - var sql = string.Format(stub, TableName, keys, vals);
247   - result.CommandText = sql;
248   - } else throw new InvalidOperationException("Can't parse this object to the database - there are no properties set");
249   - return result;
250   - }
251   - /// <summary>
252   - /// Creates a command for use with transactions - internal stuff mostly, but here for you to play with
253   - /// </summary>
254   - public DbCommand CreateUpdateCommand(object o, object key) {
255   - var expando = o.ToExpando();
256   - var settings = (IDictionary<string, object>)expando;
257   - var sbKeys = new StringBuilder();
258   - var stub = "UPDATE {0} SET {1} WHERE {2} = @{3}";
259   - var args = new List<object>();
260   - var result = CreateCommand(stub,null);
261   - int counter = 0;
262   - foreach (var item in settings) {
263   - var val = item.Value;
264   - if (!item.Key.Equals(PrimaryKeyField, StringComparison.CurrentCultureIgnoreCase) && item.Value != null) {
265   - result.AddParam(val);
266   - sbKeys.AppendFormat("{0} = @{1}, \r\n", item.Key, counter.ToString());
267   - counter++;
268   - }
269   - }
270   - if (counter > 0) {
271   - //add the key
272   - result.AddParam(key);
273   - //strip the last commas
274   - var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 4);
275   - result.CommandText = string.Format(stub, TableName, keys, PrimaryKeyField, counter);
276   - } else throw new InvalidOperationException("No parsable object was sent in - could not divine any name/value pairs");
277   - return result;
278   - }
279   - /// <summary>
280   - /// Removes one or more records from the DB according to the passed-in WHERE
281   - /// </summary>
282   - public DbCommand CreateDeleteCommand(string where = "", object key = null, params object[] args) {
283   - var sql = string.Format("DELETE FROM {0} ", TableName);
284   - if (key != null) {
285   - sql += string.Format("WHERE {0}=@0", PrimaryKeyField);
286   - args = new object[]{key};
287   - } else if (!string.IsNullOrEmpty(where)) {
288   - sql += where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase) ? where : "WHERE " + where;
289   - }
290   - return CreateCommand(sql, null, args);
291   - }
292   - /// <summary>
293   - /// Adds a record to the database. You can pass in an Anonymous object, an ExpandoObject,
294   - /// A regular old POCO, or a NameValueColletion from a Request.Form or Request.QueryString
295   - /// </summary>
296   - public object Insert(object o) {
297   - dynamic result = 0;
298   - using (var conn = OpenConnection()) {
299   - var cmd = CreateInsertCommand(o);
300   - cmd.Connection = conn;
301   - cmd.ExecuteNonQuery();
302   - cmd.CommandText = "SELECT @@IDENTITY as newID";
303   - result = cmd.ExecuteScalar();
304   - }
305   - return result;
306   - }
307   - /// <summary>
308   - /// Updates a record in the database. You can pass in an Anonymous object, an ExpandoObject,
309   - /// A regular old POCO, or a NameValueCollection from a Request.Form or Request.QueryString
310   - /// </summary>
311   - public int Update(object o, object key) {
312   - return Execute(CreateUpdateCommand(o, key));
313   - }
314   - /// <summary>
315   - /// Removes one or more records from the DB according to the passed-in WHERE
316   - /// </summary>
317   - public int Delete(object key = null, string where = "", params object[] args) {
318   - return Execute(CreateDeleteCommand(where: where, key:key, args: args));
319   - }
320   - /// <summary>
321   - /// Returns all records complying with the passed-in WHERE clause and arguments,
322   - /// ordered as specified, limited (TOP) by limit.
323   - /// </summary>
324   - public IEnumerable<dynamic> All(string where = "", string orderBy = "", int limit = 0, string columns = "*", params object[] args) {
325   - string sql = limit > 0 ? "SELECT TOP " + limit + " {0} FROM {1} " : "SELECT {0} FROM {1} ";
326   - if (!string.IsNullOrEmpty(where))
327   - sql += where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase) ? where : "WHERE " + where;
328   - if (!String.IsNullOrEmpty(orderBy))
329   - sql += orderBy.Trim().StartsWith("order by", StringComparison.CurrentCultureIgnoreCase) ? orderBy : " ORDER BY " + orderBy;
330   - return Query(string.Format(sql, columns,TableName), args);
331   - }
332   -
333   - /// <summary>
334   - /// Returns a dynamic PagedResult. Result properties are Items, TotalPages, and TotalRecords.
335   - /// </summary>
336   - public dynamic Paged(string where = "", string orderBy = "", string columns = "*", int pageSize = 20, int currentPage =1, params object[] args) {
337   - dynamic result = new ExpandoObject();
338   - var countSQL = string.Format("SELECT COUNT({0}) FROM {1}", PrimaryKeyField, TableName);
339   - if (String.IsNullOrEmpty(orderBy))
340   - orderBy = PrimaryKeyField;
341   -
342   - if (!string.IsNullOrEmpty(where)) {
343   - if (!where.Trim().StartsWith("where", StringComparison.CurrentCultureIgnoreCase)) {
344   - where = "WHERE " + where;
345   - }
346   - }
347   - var sql = string.Format("SELECT {0} FROM (SELECT ROW_NUMBER() OVER (ORDER BY {2}) AS Row, {0} FROM {3} {4}) AS Paged ",columns,pageSize,orderBy,TableName, where);
348   - var pageStart = (currentPage -1) * pageSize;
349   - sql+= string.Format(" WHERE Row >={0} AND Row <={1}",pageStart, (pageStart + pageSize));
350   - countSQL += where;
351   - result.TotalRecords = Scalar(countSQL,args);
352   - result.TotalPages = result.TotalRecords / pageSize;
353   - if (result.TotalRecords % pageSize > 0)
354   - result.TotalPages += 1;
355   - result.Items = Query(string.Format(sql, columns, TableName), args);
356   - return result;
357   - }
358   - /// <summary>
359   - /// Returns a single row from the database
  139 + /// Turns the object into a Dictionary
360 140 /// </summary>
361   - public dynamic Single(object key, string columns = "*") {
362   - var sql = string.Format("SELECT {0} FROM {1} WHERE {2} = @0", columns,TableName, PrimaryKeyField);
363   - return Fetch(sql, key).FirstOrDefault();
  141 + /// <param name="thingy">The thingy.</param>
  142 + /// <returns>A Dictionary{string, object}.</returns>
  143 + /// <remarks></remarks>
  144 + public static IDictionary<string, object> ToDictionary(this object thingy)
  145 + {
  146 + return (IDictionary<string, object>)thingy.ToExpando();
364 147 }
365 148 }
366 149 }

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.