this.Blog.Find(entry => entry.IsHelpful);
 Wednesday, June 10, 2009
WCF and IDisposable

If you’re like me (and apparently many other people), when you start using (no pun intended) WCF by creating a client channel, it’s only a matter of time before you realize that you’re probably doing it wrong. 

Problem number one is that if you don’t explicitly close the connection, it’s only a matter of time before the connection starts faulting.  So you say to yourself, “Aha!  I need to close the damn connection.  And since I’m a good .Net programmer, I see the IChannelListener interface extends the IDisposable interface so I can just wrap my call in a ‘using’ statement which will explicitly clean up all my resources no matter what happens during the method execution.”

And then an exception happens.  Even though you wrap your call in the using statement, you see this weird exception about the channel being in the faulted state (or something like that).  Wait – I wrapped my call in the using statement.  This should work!  So you fire up Google Bing and quickly learn the WCF team made the decision to implement IDisposable wrong uniquely. 

In order to get a WCF client to work as expected, you need to workaround the decision made by the WCF team and wrap all your WCF calls in blocks similar to this one:

  1: var channelFactory = new ChannelFactory(binding, endpointAddress);
  2: 
  3: var proxy = channelFactory.CreateChannel<ICustomerService>();
  4: IClientChannel clientChannel = (IClientChannel)proxy;
  5: bool isSuccessful = false;
  6: try
  7: {
  8:   proxy.AddCustomer(customer);
  9:   clientChannel.Close();
 10:   isSuccessful = true;
 11: }
 12: finally
 13: {
 14:   if ( !isSuccessful )
 15:   {
 16:     clientChannel.Abort();
 17:   }
 18: }

As you can see here, you must explicitly call Close() on the client channel unless an Exception is thrown, in which case you need to call the Abort() method.

This code doesn’t just emit a code smell of violating the DRY principle, it absolutely reeks of it.  Steve Smith (and others) have come up with extension/utility methods aimed at simplifying the call and removing the repetitive boiler plate code from the above example.  Inspired by these solutions, I’d thought I’d throw out my own answer to this problem:

  1: public class WcfClient<TInterface>
  2: {
  3:   public WcfClient(Uri uri) : this(uri, new NetTcpBinding(SecurityMode.None))
  4:   {
  5:     Uri = uri;
  6:   }
  7:   
  8:   public WcfClient(Uri uri, Binding binding) 
  9:   {
 10:     this.Uri = uri;
 11:     this.Binding = binding;
 12:   }
 13:   
 14:   public Uri Uri
 15:   {
 16:     get;
 17:     private set;
 18:   }
 19:   
 20:   public Binding Binding 
 21:   {
 22:     get
 23:     private set;
 24:   }
 25: 
 26:   public void Using(Action<TInterface> serviceAction)
 27:   {
 28:     TInterface proxy = CreateChannelFactory().CreateChannel();
 29:     IClientChannel clientChannel = (IClientChannel)proxy;
 30:     bool isSuccessful = false;
 31:     try
 32:     {
 33:       serviceAction(proxy);
 34:       clientChannel.Close();
 35:       isSuccessful = true;
 36:     }
 37:     finally
 38:     {
 39:       if ( !isSuccessful )
 40:       {
 41:         clientChannel.Abort();
 42:       }
 43:     }
 44:   }
 45: 
 46:   public TResult Using<TResult>(Func<TInterface, TResult> serviceAction)
 47:   {
 48:     TResult result;
 49:     TInterface proxy = CreateChannelFactory().CreateChannel();
 50:     IClientChannel clientChannel = (IClientChannel)proxy;
 51:     bool isSuccessful = false;
 52:     try
 53:     {
 54:       result = serviceAction(proxy);
 55:       clientChannel.Close();
 56:       isSuccessful = true;
 57:     }
 58:     finally
 59:     {
 60:       if ( !isSuccessful )
 61:       {
 62:         clientChannel.Abort();
 63:       }
 64:     }
 65: 
 66:     return result;
 67:   }
 68:   
 69:   private ChannelFactory CreateChannelFactory()
 70:   {
 71:     var endpoint = new EndpointAddress(Uri);
 72:     return new ChannelFactory(Binding, endpoint);
 73:   }
 74: }

The two Using() methods offer an overloaded way to invoke a method on the service proxy.  In the first version, you can invoke an Action call which doesn’t expect a returned value.  In the second version, the TResult generic type determines the type of value expected from the invocation of the proxy object.  The return value will flow through from the proxy call execution to the caller.  Think of these two methods as being akin to the differences between a Sub or a Function in VB (my God, did I just admit to knowing VB?!?!?!).

The WcfClient code is responsible for creating the client proxy and returns the proxy back to the calling code.  As the caller, here is how you would execute the methods:

  1: string wcfUri = ConfigurationManager.AppSettings["wcfUri"];
  2: 
  3: var wcfClient = new WcfClient<ICustomerService>(wcfUri);
  4: 
  5: wcfClient.Using(proxy => proxy.AddCustomer(new Customer()));
  6: 
  7: // ...
  8: 
  9: Customer[] customers = wcfClient.Using(proxy => proxy.GetCustomers());

The nice thing about this solution is that we take care of the exception handling and correctly clean up our resources in one place, and that logic is completely shielded from the calling code.  Plus, we can account for situations where a return value is expected versus when one is not.


Kick it on DotNetKicks.com
Tuesday, June 09, 2009 11:02:10 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  .Net | C# | WCF

 Saturday, May 16, 2009
Using Miado – Part 6

In my last post, I discussed how to use DataSet objects with Miado.  In this post, I will tackle a common problem – building dynamic queries.

ISqlQuery Interface

I have created an ISqlQuery interface that can be used to run dynamic queries.  The interface is quite simple.  It exposes three properties – IsBuilt, Parameters, and Sql – and one method – Build(). 

  1: public interface ISqlQuery
  2: {
  3:     bool IsBuilt { get; }
  4:     string Sql { get; }
  5:     IDictionary<string, object> Parameters { get; }
  6:     void Build();
  7: }    

The idea behind this design is for the Sql property represents the SQL that will eventually be run against the database.  It can be built up dynamically based on the filtering that is applied to the object.  The same goes for the Parameters property.  It represents the DB parameters that will be bound to the Sql statement.  Parameters can be added to this property in the same way they are added to a IDbStatement.  By doing so, you can still safely use parameterized queries (as opposed to dynamically substituting the variables straight in the SQL string – i.e. String.Format(“and Name=’{0}’”, name), which exposes a risk for SQL Injection attacks).

The Build() method should be the place where you put your logic to dynamically create the SQL and populate the parameters. 

  1: public class CustomerQueryByCityAndState : ISqlQuery
  2: {
  3:     private const string SELECT_CUSTOMERS_BASE_SQL =
  4:         "select CustomerID, Name, Address1, Address2, City, County, " + 
  5:         "StateCode, ZipCode " +
  6:         "from Customers " + 
  7:         "where 1=1 "; // etc...
  8: 
  9:     public CustomerQueryByCityAndState(string city, string state)   
 10:     {
 11:         City = city;
 12:         State = state;
 13:         Parameters = new Dictionary<string, object>();
 14:     }
 15: 
 16:     public string City { get; private set; }
 17:     public string State { get; private set; }
 18: 
 19:     public bool IsBuilt { get; private set; }
 20:     public string Sql { get; private set; }
 21:     public IDictionary<string, object> Parameters { get; private set; }
 22: 
 23:     public void Build() 
 24:     {
 25:         var sb = new StringBuilder();
 26:         sb.Append(SELECT_CUSTOMERS_BASE_SQL);
 27: 
 28:         // add City
 29:         sb.Append(" and City = @City ");
 30:         Parameters.Add("City", City);    
 31: 
 32:         // add State
 33:         sb.Append(" and StateCode = @State ");
 34:         Parameters.Add("State", State);
 35: 
 36:         // Populate the SQL
 37:         Sql = sb.ToString();
 38:     
 39:         // info
 40:         IsBuilt = true;
 41:     }
 42: }

Though it’s not actually being for used anything now, the last step of the Build() method should flip the IsBuilt property to True.  This is purely for information purposes at this point, but it could be informative to the calling class.

SqlQuery Abstract Class

To simplify things, I have created a base class you can use that implements the ISqlQuery interface.  It manages the Sql and the Parameters, and will automatically flip the IsBuilt property when the Build() method is called.  The only thing a derived class must do is implement the DoBuild() method, which is a template method to actual perform the logic that was previously implemented in Build().  It should contain the logic of dynamically creating the SQL and Parameters.

  1: protected abstract void DoBuild();
  2: 
  3: public virtual void Build()
  4: {
  5:     DoBuild();
  6:     IsBuilt = true;
  7: }

So the previous example above becomes much simpler…

  1: public class CustomerQueryByCityAndState : SqlQuery
  2: {
  3:     private const string SELECT_CUSTOMERS_BASE_SQL = ...
  4: 
  5:     public CustomerQueryByCityAndState(string city, string state) 
  6:     {
  7:        City = city;  
  8:        State = state;
  9:     }
 10: 
 11:     public string City { get; private set; }
 12:     public string State { get; private set; }
 13: 
 14:     public override void DoBuild() 
 15:     {
 16:         var sb = new StringBuilder();
 17:         sb.Append(SELECT_CUSTOMERS_BASE_SQL);
 18:    
 19:         sb.Append(" and City = @City ");
 20:         Parameters.Add("City", City); 
 21: 
 22:         sb.Append(" and State = @State ");
 23:         Parameters.Add("State", State); 
 24: 
 25:         Sql = sb.ToString();
 26:     }
 27: }

The disadvantage is that inheriting from this class binds you into an inheritance hierarchy, which may not be a good thing (see inheritance vs. composition).  If you need to maintain a pure inheritance hierarchy, use the interface instead, or hide the implementation of this class in an internal Property.

Filter Objects

In many cases, you probably expose a common lightweight object to the UI layer for representing a “filter” to the database.  In reality, this is nothing more than a simple Data Transfer Object (DTO) that has properties representing all the ways the data can be filtered.


A common pattern I use is to take a Filter DTO object into the Query object’s constructor and build the SQL from it dynamically:

  1: public class SiteLocatorQuery : SqlQuery
  2: {
  3:     private const string SELECT_SITES_SQL = ..
  4: 
  5:     public SiteLocatorQuery(SiteLocatorFilter filter) 
  6:     {
  7:         Filter = filter;
  8:     }
  9: 
 10:     public SiteLocatorFilter Filter { get; private set; }
 11: 
 12:     public override void DoBuild() 
 13:     {
 14:         var sb = new StringBuilder();
 15:         sb.Append(SELECT_SITES_SQL);
 16:       
 17:         if ( Filter.IsRecent ) 
 18:         { 
 19:            sb.Append(" and IsRecent = @IsRecent ");
 20:            Parameters.Add("IsRecent", 1);
 21:         }
 22:         if ( Filter.BrandID > 0 ) 
 23:         {
 24:            sb.Append(" and BrandID = @BrandID ");
 25:            Parameters.Add("BrandID", filter.BrandID);
 26:         }
 27: 
 28:         // etc...
 29: 
 30:         Sql = sb.ToString();
 31:     }    
 32: }

This has the advantage of hiding the complexity of how the SQL is built up (or the fact that we are using raw SQL at all) from the UI layer.  I normally isolate my “Query” objects to a namespace in my MyCompany.Data dll, requiring a reference to the Filter objects (and not the other way around).  Plus, the light-weight DTOs can be used to pass data in and out of the UI layer very easily, as in the case of using messaging or web services.

So I’ve got my ISqlQuery interface coded … how do I use it?

Once you have a reference to the IDatabase interface, you can simply call the RunningQuery(ISqlQuery query) method to get a reference to an IDbStatement interface.  The method will call the Build() method on your interface and use the Sql and Parameters properties to populate the IDbStatement appropriately.  Once you get the IDbStatement back, you can then proceed just as you would have otherwise.

  1: public IEnumerable<Customer> FindCustomersByFilter(CustomerFilter filter)
  2: {
  3:     var query = new CustomerQuery(filter);
  4:     this.Database
  5:         .RunningQuery(query)
  6:         .QueryForResults(row => new Customer()); // row mapping omitted
  7: }

Kick it on DotNetKicks.com
Saturday, May 16, 2009 10:13:47 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  Miado

 Friday, May 01, 2009
Using Miado – Part 5

Better late than never, eh?  Due to a crazy series of events in my life (both personally and professionally), I’ve had to put blogging on a hold for a short time.  Well, I’m back baby!  Today I’m going to continue my series on the latest Miado release.

In this post, I will discuss the use of DataSet (both generic and typed) with Miado.

Plain ol’ DataSet

If you really want to use a DataSet object, it’s dead-simple easy with Miado.  It’s just like using the Miado API for the IDbStatement, except that you don’t need to map the Result Set to a custom business object.  You just need to call the QueryForDataSet() method on the IDbStatement.

  1: public DataSet FindBlogEntriesByBlog(int blogID)
  2: {
  3:     return 
  4:         this.Database
  5:             .ExecutingSql(SELECT_BLOG_ENTRIES_BY_BLOG_ID_SQL)
  6:             .AddParameter("BlogID", blogID)
  7:             .QueryForDataSet();
  8: }
Typed DataSets

If you weren’t aware, Typed DataSet classes were introduced in 2.0 version of the .Net framework to compensate for some of the shortcomings of the original DataSet object.  Typed DataSets inherit from the DataSet class, but allow for strong typing on the rows and columns contained in the DataSet.  So instead of having to access the column values in the rows through a Dictionary key lookup, the column values now are exposed as strongly-typed properties on the Typed DataSet object itself.

On the QueryForDataSet() method detailed above, Miado exposes an optional generic typed version of the method that let’s you define the type of DataSet that will be returned.  QueryForDataSet<T>() can be used to return a strongly-typed DataSet object since T is constrained to be a subclass of DataSet.

  1: public BlogEntryDataSet FindBlogEntriesByBlog(int blogID)
  2: {
  3:     return 
  4:         this.Database 
  5:             .ExecutingSql(SELECT_BLOG_ENTRIES_BY_BLOG_ID)
  6:             .AddParameter("BlogID", blogID)
  7:             .QueryForDataSet<BlogEntryDataSet>();
  8: }
DataTable

Not surprisingly, you can also retrieve a DataTable from the IDbStatement instead of a DataSet if you are only interested in a single table’s result set.  Simply call QueryForDataTable() instead of QueryForDataSet().

  1: public DataTable FindBlogEntriesByBlog(int blogID)
  2: {
  3:     return 
  4:         this.Database
  5:             .ExecutingSql(SELECT_BLOG_ENTRIES_BY_BLOG_ID_SQL)
  6:             .AddParameter("BlogID", blogID)
  7:             .QueryForDataTable();
  8: }
Thoughts on DataSet

I consider myself to be Alt.Net, so by law I’m required to tell you not to use DataSet.  It’s funny though – I like to play devil’s advocate a lot and ask the question as to why we don’t use it more often.  I’m just as guilty as the next person in creating my share of dumb Data Transfer Objects (DTOs) that directly represent database tables.  In doing so, I am forced to manually map the columns in the result set to properties on the DTO.  Why not skip that effort and just let the DataSet (typed or regular) handle that?  It’s already built into the framework after all.  And if you’ve ever played with Rails – isn’t an ActiveRecord object effectively the same thing as a Typed DataSet???

I guess it boils down to control.  I don’t like letting go of the classes I create and can easily refactor and manipulate without having to employ or depending on tooling to do so.  It’s a personal choice.  I don’t think I’d turn my nose down at a developer who chooses to use DataSets.  That being said, I can’t remember the last time I’ve done so.

Coming up next!

In my next post (whenever that may be), I will discuss how you can use Miado to build dynamic queries.


Kick it on DotNetKicks.com
Friday, May 01, 2009 10:22:07 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  Miado

 Sunday, March 01, 2009
Using Miado – Part 4

This is part 4 in a series about the latest release of Miado.  In my last post, I discussed about creating an IDbStatement from the IDatabase interface.  In this post, I will start to discuss the main methods exposed by the IDbStatement interface.

Adding Parameters

Adding parameters to the IDbStatement is really easy.  It is accomplished simply by calling the AddParameter() method with a name/value pair.  The name should match the parameter name declared in the SQL statement and the value is what will be substituted during the query execution.  Optionally, you can also set the DBType and/or parameter direction.  If the DBType is not set, it will be inferred by the DbProvider implementation based the type of the parameter value.  The parameter direction is assumed to be an input parameter unless explicitly declared.  This routine should be very familiar to anyone who has ever done traditional ADO.Net development.

Like most other methods on the IDbStatement interface, the AddParameter() method returns a reference to itself so it can be chained with other method calls on the IDbStatement interface.  Example:

  1: private static readonly string INSERT_ADDRESS_SQL = 
  2:     "insert into Address(Address1, Address2, City, State, ZipCode) " +
  3:     "values(@Addr1, @Addr2, @City, @State, @ZipCode)";
  4: 
  5: public void SaveAddress(Address addr) 
  6: {
  7:     this.Database
  8:         .ExecutingSql(INSERT_ADDRESS_SQL)
  9:         .AddParameter("Addr1", addr.Address1)
 10:         .AddParameter("Addr2", addr.Address2)
 11:         .AddParameter("City", addr.City, DbType.String) // explicitly set DbType
 12:         .AddParameter("State", addr.State)
 13:         .AddParameter("ZipCode", addr.ZipCode)
 14:         .ExecuteNonQuery();
 15: }

If you really want total control over the parameter, you can get a reference to the actual DbParameter object using the Action<DbParameter> method signature of AddParameter().

  1: public void UpdateUser(User user) 
  2: {
  3:     this.Database
  4:         .ExecutingSql(UPDATE_USER_SQL)
  5:         .AddParameter(dbParm => 
  6:         {
  7:             dbParm.ParameterName = "Email";
  8:             dbParm.Value = user.Email;
  9:         }) // AddParameter(Action<DbParameter> dbParmAction)
 10:         .AddParameter(dbParm => 
 11:         { 
 12:             dbParm.ParameterName = "UserID";
 13:             dbParm.Value = user.UserID;
 14:             dbParm.DbType = DbType.Int32;
 15:             dbParm.ParameterDirection.Input;
 16:         }) // dbParm is a DbParameter
 17:         .ExecuteNonQuery();
 18: }
Insert/Update/Delete

Anytime you want to execute a SQL statement that does not return a result set, you can call the ExecuteNonQuery() method (you probably already realized this fact from previous examples).  I’ve thought about adding explicit Save(), Update(), and Delete() methods to the API for clarity sake, but since I’m not providing an ORM, these methods would only be information and could not be guaranteed to perform their exact intended action.  In other words, they would merely wrap the ExecuteNonQuery() method, so you could call the Save() method to in fact execute a “delete from User where UserID = @ID” SQL statement with no problems.  I would be interested to see what other people thought about this change in the comments.  Does the readability of Save(), Update(), and Delete() outweigh the need to validate whether the right one is called?  Should there be validation against the raw SQL when one of these methods is called (e.g. explicitly checking the SQL string for “INSERT” when Save() is called)?  The validation method option is the route I’m leaning.

Creating Custom Business Objects

When you call QueryForResults() or QueryForOne(), you must use a generic type to declare the type of object that will be created from each row in the result set.  Your job will be to create an object for each row as the cursor moves forward in each iteration by mapping the values from the columns in the result set row.  Most of the time, this will be a custom business object.  However, it could be something as simple as an int if you are just returning a count(*).  Both these method types take a delegate that passes in an IResultSetRow interface (which merely wraps a DbDataReader) and return an instance of the generic type you declared.  The IResultSetRow interface has both typed  - using generics GetValue<T>() - and non-typed - GetValue() - methods that can be used to retrieve values using ordinals or by column name.

If your return type is simple or will not likely be re-used, you can use a lambda expression to create the returned object.

  1: private static readonly SELECT_USER_COUNT_SQL = "select count(*) from Users";
  2: 
  3: public int FindUserCount() 
  4: {
  5:     return 
  6:         this.Database
  7:             .ExecutingSql(SELECT_USER_COUNT_SQL)
  8:             .QueryForOne<int>(row => row.GetValue<int>(0));
  9: }

Alternatively, you can create a true delegate method that satisfies the signature required by the QueryForOne() and QueryForResults() methods and pass a reference to the delegate.

  1: public IEnumerable<BlogEntry> FindBlogEntriesByBlog(int blogID)
  2: {
  3:     return 
  4:         this.Database
  5:             .ExecutingSql(SELECT_BLOG_ENTRIES_BY_BLOG_ID_SQL)
  6:             .AddParameter("BlogID", blogID)
  7:             .QueryForResults<BlogEntry>(CreateBlogEntry);
  8: }
  9: 
 10: private BlogEntry CreateBlogEntry(IResultSetRow row) 
 11: {
 12:     return new BlogEntry 
 13:     {
 14:         BlogEntryID = row.GetValue<int>("BlogEntryID"),
 15:         Text = row.GetValue<string>("BlogText")
 16:         // rest of mapping ommitted
 17:     };
 18: }

In my next post, I will describe how to use the IDbStatement to return our old friend DataSet.


Kick it on DotNetKicks.com
Sunday, March 01, 2009 5:29:02 PM (Eastern Standard Time, UTC-05:00)  #    Comments [2]  Miado

 Tuesday, February 17, 2009
Using Miado – Part 3

This is part 3 in a series about the new release of Miado.  If you want, you can go back and see Part 1 and Part 2 where I talk about creating an IDatabase reference.  In this part, I will discuss how to use the IDatabase to create an IDbStatement.

IDbStatement

The IDbStatement interface is the main working component of the Miado API.  You need to use this interface to run raw SQL or to execute a stored procedure.  Once you get a handle on the interface (from the IDatabase interface), you can begin “building” the statement that will be run against the DB.  Most of the methods on the interface return a reference to itself, so the method calls can be chained to form a fluent-type interface.

Executing SQL

Most of the time, I use raw SQL to execute my DB statements.  The ExecutingSql() method on the IDatabase interface returns an IDbStatement reference.

  1: public class ProductRepository : IProductRepository
  2: {
  3:     private static readonly string SELECT_PRODUCT_BY_ID = 
  4:         "select ProductID, Name, ProductNumber, Color, ListPrice, ProductModel " + 
  5:         "from Products " +
  6:         "where ProductID = @ID";
  7: 
  8:     // more SQL 
  9: 
 10:     public ProductRepository(IDatabase db) 
 11:     {
 12:         this.Database = db;
 13:     }
 14: 
 15:     public IDatabase Database 
 16:     {
 17:         get;
 18:         private set;
 19:     }
 20: 
 21:     public Product Load(int productID) 
 22:     {
 23:         IDbStatement dbStmt = this.Database.ExecutingSql(SELECT_PRODUCT_BY_ID);
 24:         dbStmt.AddParameter("ID", productID);
 25:         return dbStmt.QueryForOne<Product>(CreateProduct);
 26:     }
 27: 
 28:     // more CRUD methods
 29: 
 30:     private Product CreateProduct(IResultSetRow row)
 31:     {
 32:         // implementation omitted...
 33:     }
 34: } 

As I said before, since the methods on the IDbStatement return themselves, you can chain the calls.  In line 21-26, you could change the Load() method to read like this:

  1: public Product Load(int productID) 
  2: {
  3:     return 
  4:         this.Database
  5:             .ExecutingSql(SELECT_PRODUCT_BY_ID)
  6:             .AddParameter("ID", productID)
  7:             .QueryForOne<Product>(CreateProduct);
  8: }
Stored Procedures

Stored Procedures are built up in a similar fashion, except you need to call the CallingStoredProcedureNamed() method to load the SP.

  1: public class EmployeeRepository : IEmployeeRepository
  2: {
  3:     public EmployeeRepository(IDatabase db)
  4:     { 
  5:         this.Database = db;
  6:     }
  7:  
  8:     public IDatabase Database 
  9:     {
 10:         get;
 11:         private set;
 12:     }
 13: 
 14:     public IEnumerable<Employee> FindEmployeesByManager(int mgrID) 
 15:     {
 16:        return 
 17:           this.Database
 18:               .CallingStoredProcedureNamed("uspGetManagerEmployees")
 19:               .AddParameter("ManagerID", mgrID)
 20:               .QueryForResults<Employee>(CreateEmployee);
 21:     }
 22: 
 23:     private Employee CreateEmployee(IResultSetRow row) 
 24:     {
 25:         // implementation omitted
 26:     }
 27: }
Registered Queries

I showed in my last post how you can use the IDatabase interface to “register” queries.  You can easily retrieve them in the IDbStatement interface by using LoadQueryRegisteredAs() method, which will load the corresponding SQL.

  1: public IEnumerable<State> FindAllStates() 
  2: {
  3:     return 
  4:         this.Database 
  5:             .LoadQueryRegisteredAs("SelectStates")
  6:             .QueryForResults<State>(
  7:                 row => new State 
  8:                 { 
  9:                     Abbreviation = row.GetValue<string>("StateCode"), 
 10:                     Name = row.GetValue<string>("Name") 
 11:                 });
 12: }                
Running Custom Queries

There is one more way to “load” a query in the IDbStatement interface, and that is by calling the RunningQuery() method, and passing in an object that implements the ISqlQuery interface.  That is new functionality to this release and probably deserves its own blog post, so I will cover that later.

In my next post, I will discuss how the IDbStatement executes and discuss the different kinds of return types available, and how you can create custom business objects from the query result set.


Kick it on DotNetKicks.com
Tuesday, February 17, 2009 4:40:52 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  Miado

 Monday, February 16, 2009
Using Miado - Part 2

This is part 2 in a series on the new updates to the Miado API.  You can read the first part in the series here.  In this post, I am going to discuss some of the new features available when configuring Miado.

Query Registration

I’ve had a couple of clients who’ve had a requirement where they wanted to store their SQL in a single location rather than spread across the Repository objects as embedded SQL.  In fact, one client put all their SQL in .sql files and stored them on the file system.  I had never seen this before, but after working with it for a while I definitely warmed up on the idea.  I definitely saw some advantages for doing this:

  • Versioning – it’s very easy to isolate changes to individual SQL statements, and you can take advantage of all the benefits of using a version control system, like labeling, diffs, branching, etc.
  • Testing - you can open the SQL files directly in your DB management software to test the queries (as opposed to cutting and pasting out your source code, where you have to remove code formatting like string concatenations)
  • Collaboration – you can easily share the queries with a DBA, who can help tweak them or run profiling tools against them
  • Isolation – all your queries are stored in a common well-known place

So I added the capability in Miado to “register” queries by name.  You can either do this manually or by pointing to files or a directory on the file system.  The IQueryRegistry interface controls the registration and retrieval of stored queries.  To get an access to this interface, you need to declare an Action<IQueryRegistry> delegate to configure itself.  The delegate is passed in via a method on the IDatabase interface.

Registering Queries Manually

The easiest way to register queries is by setting name/value pairs:

  1: var db = new SqlServerDatabase(connString);
  2: db.ConfigureQueryRegistry(queryRegistry => 
  3:     {
  4:         string name = "SelectStates";
  5:         string sql = "select StateCode, Name from States";
  6:         queryRegistry.RegisterQuery(name, sql);
  7: 
  8:         string name1 = "SelectUserByID";
  9:         string sql1 = "select UserID, Email " +
 10:                       "from Users " + 
 11:                       "where UserID = @ID";
 12:         // NamedQuery is a simple name/value pair object
 13:         var namedQuery = new NamedQuery(name1, sql1);
 14:         queryRegistry.RegisterQuery(namedQuery);
 15:     });
Registering Queries From Files

Alternately, you can register queries from files on the file system.  There are multiple ways to do this.  First of all, you can start at a selected directory and optionally pass a Predicate to select only certain files.  From the resulting files, you need to build a NamedQuery list from each individual file.

  1: var db = new SqlServerDatabase(connString);
  2: db.ConfigureQueryRegistry(queryRegistry =>
  3:     {
  4:         // start looking in the "sql" directory for files named *.sql
  5:         queryRegistry.RegisterQueriesFromPath(
  6:             "sql", 
  7:             fileInfo => String.Compare(fileInfo.Extension, ".sql") == 0,
  8:             fileInfo => 
  9:             {
 10:                 string queryName = fileInfo.Name.Substring(0, fileInfo.Name.IndexOf('.'));
 11:                 string sql = File.ReadAllText(fileInfo.FullName);
 12:                 return new NamedQuery[] { new NamedQuery(queryName, sql) };
 13:             });
 14:     });

You can also pass in the specific files you want processed:

  1: var db = new SqlServerDatabase(connString);
  2: db.ConfigureQueryRegistry(queryRegistry => 
  3:     {
  4:         // find the files yourself
  5:         string[] files = Directory.GetFiles("sql", "*.sql", SearchOption.AllDirectories);
  6:         queryRegistry.RegisterQueriesFromFiles(
  7:             files, 
  8:             fileInfo =>
  9:             {
 10:                 string queryName = fileInfo.Name.Substring(0, fileInfo.Name.IndexOf('.'));
 11:                 string sql = File.ReadAllText(fileInfo.FullName);
 12:                 return new NamedQuery[] { new NamedQuery(queryName, sql) };
 13:             });
 14:     });
Be Smart

Obviously, you need to be careful about exposing the raw SQL in any directory that can be compromised.  If you are using a web app, make sure it is not in a publicly visible folder.  If you are using a rich client app, you might want to think about using Isolated Storage as your underlying query repository.

In my next post, I will show how to use the IDbStatement to run queries, including those registered in the IQueryRegistry.


Kick it on DotNetKicks.com
Monday, February 16, 2009 1:00:13 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  Miado