July 22, 2008 by
ryan
I really wish Visual Studio / SQL Server Management Studio had column editing support similar to text editors like Crimson Edit. I find myself using the column edit alot when running quick, one off SQL Queries or making the same change to multiple lines in VS. I know a lot of this functionality can be replicated with macros but it seems to be a lot faster to just hit column editing mode and type away.
View my demo of Crimson Editor's Column Edit Mode. (Wink seems to slow down and speed up certain parts of the recording -- especially when a dialog window is open.)
July 8, 2008 by
ryan
Justin Etheredge recently tagged me to write up how I got started in software development (you are probably familiar with the meme started by Michael Eaton). Without any further explanation, here goes:
How old were you when you first started programming?
I first started programming when I was 10 or 11 (I don't remember exactly).
How did you get started in programming?
My interest in programming initially began as a general interest in computer games. My dad showed me how to get around in DOS and pulled up some games in QBasic. It wasn't long after that I started messing with the code to see what would happen if I changed things. From there, I tried writing some stuff on my own spending a lot of time in the syntax help.
What was your first language?
BASIC
What was the first real program you wrote?
Depending on the definition, the first real program I wrote was a game that worked in an AOL chat room. When I was 13, one of my friends showed me this thing called a scrambler. The scrambler would let you enter a word, send the scrambled word to the chat and keep score of who got the word right first, etc. I don't know why but I thought it would be an interesting thing to try and replicate. About a month later, I had finished writing one using the VB and the Windows API. It was not very useful but I learned a lot that way I guess.
What languages have you used since you started programming?
C#, VB.NET, Java, JavaScript, Ruby, Perl, PHP, BASIC, C, C++, F# (and others)
What was your first professional programming gig?
When I was in Highschool/College I did some freelance websites/applications mainly for construction and contracting companies. After college my first full-time programming job was working at Franklin University on the development team (websites / web applications).
If you knew then what you know now, would you have started programming?
Absolutely.
If there is one thing you learned along the way that you would tell new developers, what would it be?
Be continuously learning.
What's the most fun you've ever had programming?
I honestly couldn't tell you -- there are a lot of projects that have been really fun. I especially like when there's some new kind of challenge I haven't encountered before.
Who are you calling out?
Matt Braun
Scott Sanzenbacher
Jurgen Appelo
Danny Douglass
Oren Eini
June 11, 2008 by
ryan
Whether you're creating a project for fun or freelancing (etc.),
working remotely as part of a team is becoming more and more common.
Communication is still key to a successful project, however, it's much
more difficult when your working with people in different locations and
on different schedules. Although, you will not be able to achieve the same
level of communication as face-to-face, there are some tools beyond
E-mail, IMs and Remote Desktop that could make your life a little
easier. Here are some of the tools I use when I'm not in the vicinity of as the team I'm working with.
Source Control
Obviously,
source control is a must-have. This is a given for development
projects; even if you're working by yourself. I use Subversion for all
of my code because it's relatively easy to set up and, for the most part,
pretty intuitive for newer users. When creating a source repository you
need to choose to:
- Host your own
- Go through a third party
- Assembla
-Although there are many options in this arena, this is the host that I
use for remote collaboration so it's the one I'm going to focus on. You
can set up a Subversion repository simply by adding a new project to
your workspace and specifying that you want to use subversion (in the
setup configuration). From there you can add users or make your project
open to the public. Apart from Subversion, there are many other features
that may make Assembla a worthwhile site to check into.
Finally when running Subversion, you're either going to need
an IDE that supports SVN, use the command line or download a client. I
use
Tortoise SVN and the command prompt, however,
Visual SVN for Visual
Studio looks nice (and when I'm using Eclipse, the SubVersion plugin is
wonderful).
Screen capture software
It
can be confusing trying to fix an issue based on a text description.
Having a screenshot or video that explains how to reproduce a bug can
be invaluable. Coupled with a bug tracking application, this can be an
extremely effective way to quickly resolve issues. Camtasia is
probably the ideal application for creating screen casts of a bug but
for the price tag it might be overkill (especially if it's just for fun
/ open source). Currently, I usually use Wink by Debug mode for this
sort of functionality. Although it's definitely not as feature rich as
Camtasia, it gets the job done.
Also see: Jing
Real-Time Collaboration
Some
situations require an extra level of involvement from team members.
Vyew has been an awesome addition to the tool belt. With it, I can
collaborate / share desktop / share files real time with someone else
anywhere in the world in. Similar to the screen capture application, it
really helps to communicate something that otherwise may be difficult to
explain. Earlier in the week, for example, I was having some trouble
with an Eclipse setting for a project I'm working on. Rather than sending e-mails back and forth trying to explain the issue, I used Vyew to
share my desktop with a friend half way across the country. In a
matter of minutes, he was able to diagnosis the problem and I was back in business. Vyew is free if you don't mind having ads on the page. Otherwise, it's $6.95/month for the Plus Package and $13.95/month the Professional version. For more information, vist the Vyew site or check-out Guy Kawasaki's synopsis of Vyew.
What tools do you use to stay connected with your team?
June 5, 2008 by
ryan
This may be common knowledge but it was new to me. If you're ever hand mangling control position in a winforms designer you can setup keybindings for Bring to Front Send to Back options that are normally available on the controls context menu. This is really useful if you have layers of controls and you can't always get to the Context.
- Click on Tools -> Options
- Under Environment, Select the Keyboard menu
- Type "Format.BringtoFront" (or "Format.SendtoBack") in the "Show Commands Containing" box
- Choose your shortcut keys
- Press Assign
Thanks to my friend Ross for pointing this out.
June 3, 2008 by
ryan
Settings
Up until now, we've been using NHibernate Query Generator for all of our data access. Although this is a great way to retrieve our data, there is another option we can play around with -- LINQ for NHibernate. To set this up in our existing application (see Part 1, Part 2, Part 3 and Part 4 on creating the ASP.NET MVC Application) we'll first need to grab the code out of subversion https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/experiments/NHibernate.Linq/ and build it using MSBuild or Visual Studio. After that we want to add a reference to it in our application.
Simple Code
Next we'll want to update our controller to use Linq for NHibernate instead of NHQG (Service layer would be better place for this type of code but since this is a demo it'll be okay -- for more on using a service layer to handle all the repository code check out Michael Hanney's post on ActiveRecord, NHibernate and ASP.NET MVC). The initial NHGQ code is:
var p = Repository<Product>.FindOne(Where.Product.Title == ID);
Our LINQ for NHibernate query will look like this:
var p = (from item in UnitOfWork.CurrentSession.Linq<Product>()
where item.Title == ID
select item).First();
It's pretty obvious that the Linq code is a bit longer than the NHQG code. Although that in itself is not a bad thing, it may turn some people away. Momentarily, we'll see some scenarios where Linq for NH is very useful.
Paging and Sorting
One nice thing we can easily do with Linq for NHibernate is page and sort our data. If we simply want to get a list of all products it would look like this.
var p = (from item in UnitOfWork.CurrentSession.Linq<Product>()
select item
).ToList()
To page/sort the data it's just a slight addition to the list all code.
int itemsPerPage = 5;
int startIndex = (ID.Value - 1)* itemsPerPage;
var p = (from item in UnitOfWork.CurrentSession.Linq<Product>()
orderby item.Title ascending
select item
).Skip(startIndex).Take(itemsPerPage).ToList();
More Advanced Usage
Kyle Baley's article on Linq for Nhibernate shows a more interesting use for Linq for NHibernate; we can create a generic method that adds query criteria on the fly. This would make our code much more reusable so we're going to go ahead and make a demo class heavily based on these concepts.
public class QueryHandler<T>
{
private IList<linqExpression.Expression<Func<T, bool>>> _criteria;
public QueryHandler()
{
_criteria = new List<linqExpression.Expression<Func<T, bool>>>();
}
public void AddCriteria(linqExpression.Expression<Func<T, bool>> LambdaFunc)
{
_criteria.Add(LambdaFunc);
}
public IList<T> GetList()
{
var query = from item in UnitOfWork.CurrentSession.Linq<T>()
select item;
//Tack on our query Criteria
foreach (var criterion in _criteria)
{
query = query.Where<T>(criterion);
}
return query.ToList();
}
}
Here, we've created a class that has a private list of criteria, a method to add criteria to the list and a method to get the list based on the given criteria. I realize it may be a little intimidating but we can perfom most of our select queries through this method due to the use of Generics.
Updating the controllers to use this functionality is not too difficult. For pages that simply retrieve lists we call the GetList method without specifying any criteria:
var queryHandler = new QueryHandler<Product>();
var p = queryHandler.GetList().Skip(startIndex).Take(itemsPerPage).ToList();
Pass in new lambda expressions to add query criteria
var queryHandler = new QueryHandler<Product>();
queryHandler.AddCriteria(item => item.Title == ID);
var p = queryHandler.GetList().First();
Now we see there are multiple options for interacting with our ActiveRecord Repository. Please let me know of any changes that you would make. I've updated the demo code in Assembla -- http://svn2.assembla.com/svn/NHibernateTest - Standard disclaimer does apply (some of the code is less than ideal but for learning it should be okay).
May 26, 2008 by
ryan
Finally we're to the point where we can see all our hard work come together. We have most of the hard work done but we still have a lot of ground to cover. If you haven't been following along, please check out Setting Up The Assemblies, Configuring the Application and Developing the Model.
Unit of Work
In some of my initial tests with NHibernate and ASP.NET MVC Pattern I kept seeing the benefits of having a Unit of Work or Session Per Request (that is opening and closing the NHibernate session at the begining and end of the http request respectively). To Recap a little, I started to write my own Session Per Request, however, Chad Myers pointed me to the Rhino Commons project which already implemented this. I think it's worthwhile becuase I don't really like putting NHibernate session code in my controller plus as Martin Fowler writes
A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work.
Luckily, with RhinoCommons, it's pretty easy to implement this pattern (check out Ayende's post on this). In a standard web forms application, we would normally create a Global.aspx that inherits UnitOfWorkApplication. Since we're using ASP.NET MVC, however, we don't necessarily want to go that route. As Michael Hanney notes on his post on MVC and Castle we can have our Global.asax inherit from UnitOfWorkApplication.
public class GlobalApplication : UnitOfWorkApplication
{
public override void Application_Start(object sender, EventArgs e)
{
base.Application_Start(sender, e);
RegisterRoutes(RouteTable.Routes);
}
...
}
If you know of another way to do this, please be sure to let me know. Also, the routing still works as it normally would -- we're just running this code first to instantiate the UnitOfWork.
In our controllers we can call our reference our Hibernate repositories and classes without specifying an ISession.
public ActionResult InsertProductGroup(string Title)
{
ProductGroup pg = new ProductGroup();
pg.Title = Title;
Repository<ProductGroup>.Save(pg);
UnitOfWork.Current.Flush();
return RenderView("AddProductGroup");
}
Notice we're still flushing our data -- but it makes the controllers a LOT cleaner. Imagine if we had to instantiate and clean up our session in each controller.
One further thing, the UnitOfWorkApplication supports both short and long conversations. I'm not going to go too much into that but if your application requires keeping objects around for a couple HTTP Requests before saving to the database Long Conversation may be the way to go. See Ayende's Wiki for more on this
NHibernate Query Generator
In the first post of this series we looked at what it takes to setup NHibernate Query Generator (NHQG from here out). Now we get to use it to make some really nice looking code (in a later post, however, we'll be using LINQ to NHibernate). If we've set up the tool as mentioned in the first post (listed earlier), all we have to do is run the tool and make sure the generated code is added to the project.
NHQG lets us use a fluent interface to set filters on our Hibernate queries; this results in code that, in my opinion, is very easy to write and understand later on. If we wanted to Find one Product with a specific title, our code would look something like this:
public ActionResult ViewProduct(string ID)
{
var p = Repository<Product>.FindOne(Where.Product.Title == ID);
if (p != null)
{
return RenderView("DisplayProduct",
p);
}
return RenderView("DisplayProduct");
}
The Where.Product.Title == ID is all from the NHQG autogenerated code. Now we actually have something to show for all our configuration and setup work. Soon, we're going to take a look at using LINQ to NHibernate instead of NHQG. In the meantime, I have checked all the code in to my svn at Assembla. My standard disclaimer on demo code applies here too :) This is just demo code for the sake of example. Some of it is far from ideal but great for learning.
Check out / update with SubVersion from the following location: http://svn2.assembla.com/svn/NHibernateTest
May 22, 2008 by
ryan
We're going to keep moving now that everything is setup (see part one for setup) and configured (see part two for configuration).
First off we are going to create our classes. The original classes and SQL tables are posted below (these may look familiar -- they are from my initial NHibernate post)
Initial Product
public class Product
{
private IList<Product> _RelatedProducts;
private IList<ProductGroup> _ProductGroups;
public Product()
{
_RelatedProducts = new List<Product>();
_ProductGroups = new List<ProductGroup>();
}
public virtual string ID { get; private set; }
public virtual string Title { get; set; }
public virtual string ImagePath { get; set; }
public virtual string Description { get; set; }
public virtual IList<Product> RelatedProducts
{
get { return _RelatedProducts; }
set { _RelatedProducts = value; }
}
public virtual IList<ProductGroup> ProductGroups
{
get { return _ProductGroups; }
set { _ProductGroups = value; }
}
}
Initial ProductGroup
public class ProductGroup
{
public virtual string ProductGroupID { get; set; }
public virtual string Title { get; set; }
public virtual IList<Product> Products { get; set; }
}
SQL Tables
CREATE TABLE [dbo].[SimpleProducts](
[ProductID] [char](32) NOT NULL,
[Title] [nvarchar](50) NOT NULL,
[ImagePath] [nvarchar](300) NULL,
[Description] [nvarchar](500) NULL
)
CREATE TABLE [dbo].[RelatedProductsLookup](
[ProductID] [char](32) NOT NULL,
[RelatedProductID] [char](32) NOT NULL
)
CREATE TABLE [dbo].[ProductsProductGroupsLookup](
[ProductGroupID] [char](32) NULL,
[ProductID] [char](32) NULL
)
CREATE TABLE [dbo].[ProductGroups](
[ProductGroupID] [char](32) NOT NULL,
[Title] [nvarchar](50) NULL
ActiveRecord Classes
In a traditional NHibernate application, we would write usually our mapping files at this time(see my other NHibernate post for more on that). Since we're using the ActiveRecord pattern, however, we can specify all our mappings inline with the classes. It is important to note that this would not be a pure domain because we're placing our mappings inside the model. Warning if you're sensitive to using Attributes this may not be the code for you...
Our classes will now begin with an ActiveRecord attribute over the class; our properties will begin with Property/HasAndBelongsToMany/etc. Please note, for the sake of the example, I'm being extremely verbose with my attributes. If your table/column names match the class/property names, some of the additional info in the attribute is not necessary.
[ActiveRecord(Table="SimpleProducts")]
public class Product
{
private IList<Product> _RelatedProducts;
private IList<ProductGroup> _ProductGroups;
public Product()
{
_RelatedProducts = new List<Product>();
_ProductGroups = new List<ProductGroup>();
}
[PrimaryKey(Column="ProductID", Generator=Castle.ActiveRecord.PrimaryKeyType.UuidHex)]
public virtual string ID { get; private set; }
[Property(NotNull=true, Length=50, Column="Title")]
public virtual string Title {get; set; }
[Property(Length=300, NotNull=false, Column="ImagePath")]
public virtual string ImagePath { get; set; }
[Property(NotNull = false, Length = 500, Column="Description")]
public virtual string Description { get; set; }
[HasAndBelongsToMany(Table="RelatedProductsLookup", ColumnKey="ProductID", ColumnRef="RelatedProductID")]
public virtual IList<Product> RelatedProducts
{
get { return _RelatedProducts; }
set { _RelatedProducts = value; }
}
[HasAndBelongsToMany(Table="ProductsProductGroupsLookup", ColumnKey="ProductID", ColumnRef="ProductGroupID")]
public virtual IList<ProductGroup> ProductGroups
{
get { return _ProductGroups; }
set { _ProductGroups = value; }
}
}
[ActiveRecord(Table="ProductGroups")]
public class ProductGroup
{
[PrimaryKey(Column="ProductGroupID", Generator=Castle.ActiveRecord.PrimaryKeyType.UuidHex)]
public virtual string ProductGroupID { get; set; }
[Property(NotNull=true, Length=50, Column="Title")]
public virtual string Title { get; set; }
[HasAndBelongsToMany(Table="ProductsProductGroupsLookup", ColumnKey="ProductGroupID", ColumnRef="ProductID")]
public virtual IList<Product> Products { get; set; }
}
Repository Object
Another added benefit of using the Castle Active Record library is that we can use the Repository<T> for all of our object persistence. Instead of creating our own implementation of IRepository, we can write code like this to save / retrieve / update objects.
Selecting an object (our product IDs are HEX UUID's so this is not exactly accurate)
var p = Repository<Product>.Get(23);
Saving / Updating
Repository<Product>.Save(p);
The repository is pretty nice -- we can save all of our objects outside of the domain, which makes for a much cleaner design. Next time, we'll be looking at the extremely simple MVC application powered by this model and NHibernate Query Generator. Continue to Part 4
May 20, 2008 by
ryan
Following up on my last post, we're going to setup a project and get everything ready for the code (we'll be doing the coding very soon -- I promise). First off, create a new MVC application (make sure you're using the latest preview from codeplex) and a new Class library. From here, you'd normally want to want to do some TDD to create your model but that's a little outside the scope of this example.
Add the references to Boo, Castle, NHibernate, RhinoCommons and Log4Net to the MVC application. In the class library, add Castle.ActiveRecord, Iesi.Collections, NHibernate, Rhino.Commons and Rhino.Commons.NHibernate. Switch over to your web.config file and Underneath the ConfigSections node add the following custom tags:
<section name="activerecord" type="Castle.ActiveRecord.Framework.Config.ActiveRecordSectionHandler, Castle.ActiveRecord" />
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="Rhino.Commons.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</sectionGroup>
Next add the specific custom tag properties somewhere after the </ConfigSections> :
<activerecord isWeb="true">
<config>
<add key="hibernate.connection.driver_class"
value="NHibernate.Driver.SqlClientDriver" />
<add key="dialect"
value="NHibernate.Dialect.MsSql2005Dialect" />
<add key="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider" />
<add key="hibernate.show_sql"
value="false" />
<add key="connection.connection_string" value="Data Source=___________;Initial Catalog=NHibernateTest;Integrated Security=True" />
</config>
</activerecord>
These active record settings should be pretty straight-forward but for more information on specific dialects or other properties check out the
Castle's Configuration Reference. Be sure to swap out my Data Source and Initial Catalog settings with yours.
<applicationSettings>
<Rhino.Commons.Properties.Settings>
<setting name="WindsorConfig"
serializeAs="String">
<value>windsor.boo</value>
</setting>
</Rhino.Commons.Properties.Settings>
</applicationSettings>
With this tag, we're telling Castle that we're going to configure Windsor with a boo file instead of an xml document.
Ayende Rahien pointed out in the comments that this tag is no longer necessary as long as the file is named windsor.boo
Windsor Configuration With Boo
Up until this point, we've been dealing with the web.config to configure our application -- now we want to configure Windsor but instead of using another xml file, we're going to use a boo file. What is Boo you might ask? According to wiki...
Boo is an object oriented, statically typed programming language developed starting in 2003, which seeks to make use of the Common Language Infrastructure support for Unicode, internationalization and web style applications, while using a Python-inspired syntax and a special focus on language and compiler extensibility.
The mere fact that you can use a programming language instead of an XML file to configure Windsor is pretty sweet. I would be lying if I claimed to know boo very well, however, the Exesto and Hibernating-Forums samples (from the Rhino-Tools project) have enough information to get you up and running. I plan on learning boo well enought to create my own config files from scratch but in the mean time, here's what my boo file looks like (heavily influenced by the sample applications mentioned above)...
import Rhino.Commons
import System.Reflection
import Castle.Core
import Castle.Services.Transaction
import Castle.Facilities.AutomaticTransactionManagement
activeRecordAssemblies = ( Assembly.Load("ProductModelActiveRecord"), )
Component("active_record_repository", IRepository, ARRepository)
Component("active_record_unit_of_work",
IUnitOfWorkFactory,
ActiveRecordUnitOfWorkFactory,
assemblies: activeRecordAssemblies )
Check out Ayende's comment for a more succinct way to register these components.
As you might have noticed, I still have to set up the colors for boo files in Visual Studio :) What this file is doing is loading the assemblies and setting up the repository / unit of work (we'll see those in action in the next parts of this series). Your project configuration should be all set. Next time we will actually be writing some code so stick around for that. View Part Three - The Model