 Friday, May 30, 2008
New release of Miado
This new release contains significant changes. First and foremost, all the implementation classes have had their public scope removed, so you will now have to program exclusively against the interfaces. I have also moved the IMiadoDao interface to IMiadoRepository in order to encourage composition and not force an inheritance hierarchy. Combined with that change, I also moved the functionality from SimpleSql into IMiadoRepository, as well as making that interface the point where you access an IDbStatement, making the IMiadoRepository the main worker module of Miado. Another change is that you need to use the MiadoRepositoryFactory to create an instance of the IMiadoRepository. Enough with the talk, let's see some code... public AdddressDao { private static readonly string INSERT_ADDRESS_SQL = "insert into Address(Address1, Address2, City, State, ZipCode) " + "values(@Addr1, @Addr2, @City, @State, @ZipCode)"; private static readonly string SELECT_ADDRESS_SQL = "select AddressId, Address1, Address2, City, " + "State, ZipCode " + "from Address "; private static readonly string SELECT_ADDRESS_BY_ID = SELECT_ADDRESS_SQL + "where AddressId = @Id "; private static readonly string SELECT_ADDRESS_BY_ZIP_CODE = SELECT_ADDRESS_SQL + "where ZipCode = @ZipCode "; private static readonly string SELECT_COUNT_BY_STATE = "select count(*) from Address where State = @State ";
// uses MiadoRepositoryFactory.CreateMiadoRepository() public AddressDao() : this(MiadoRepositoryFactory.CreateMiadoRepository( SqlClientFactory.Instance, ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString)) {}
public AdddressDao(IMiadoRepository repository) { this.MiadoRepository = repository; } protected IMiadoRepository MiadoRepository { get; set; } public void SaveAddress(Address addr) { // uses SQL right in IMiadoRepository this.MiadoRepository .ExecuteNonQuery(INSERT_ADDRESS_SQL, addr.Address1, addr.Address2, addr.City, addr.State, addr.ZipCode) } public ICollection<Address> FindAddressesByZipCode(string zipCode) { // build IDbStatement and do the mapping in a lambda expression ICollection<Address> addresses = this.MiadoRepository .CreateDbStatement(SELECT_ADDRESS_BY_ZIP_CODE) .AddParameter("ZipCode", zipCode) .QueryForResults<Address>( row => new Address() { AddressId = row.GetValue<int>("AddressId"), Address1 = row.GetValue<string>("Address1"), Address2 = row.GetValue<string>("Address2"), City = row.GetValue<string>("City"), State = row.GetValue<string>("State"), ZipCode = row.GetValue<string>("ZipCode") }); return addresses; } public Address LoadAddress(int addrId) { // uses delegate method to do the mapping return this.MiadoRepository .CreateDbStatement(SELECT_ADDRESS_BY_ID) .AddParameter("Id", addrId) .QueryForOne<Address>(CreateAddress); } public int FindCountByState(string state) { return this.MiadoRepository .CreateDbStatement(SELECT_COUNT_BY_STATE) .AddParameter("State", state) .QueryForOne<int>(row => row.GetValue<int>(0)); } private static Address CreateAddress(IResultSetRow row) { return new Address() { AddressId = row.GetValue<int>("AddressId"), Address1 = row.GetValue<string>("Address1"), Address2 = row.GetValue<string>("Address2"), City = row.GetValue<string>("City"), State = row.GetValue<string>("State"), ZipCode = row.GetValue<string>("ZipCode") }; } }
Friday, May 30, 2008 10:57:03 PM (Eastern Standard Time, UTC-05:00) .Net | C# | Miado
 Wednesday, April 30, 2008
Using Miado with Powershell
One of the nice things about Miado is that it wraps a lot of tedious, repetitive ADO.Net code and therefore greatly reduces the amount of code you actually do need to write. Here's a quick example. One of the tasks I had to do at my last last gig was upload a set of prices from a CSV file every month. I wrote a PowerShell script to use Miado to do the DB inserts:
- function BuildSql()
- {
-
- $sb = New-Object System.Text.StringBuilder
- $sb.Append("insert into VendorPrice(VendorID, FixedPrice, VariablePrice, ");
- $sb.Append("CreationDate, LastUpdatedDate) ");
- $sb.Append("values(@VendorID, @FixedPrice, @VariablePrice, ");
- $sb.Append("current_timestamp, current_timestamp)");
-
- return $sb.ToString();
- }
-
- [Reflection.Assembly]::LoadFile("C:\dev\VS2008\Miado\src\Miado\bin\Release\Miado.dll")
-
-
- $connString = "Data Source=.\SQLEXPRESS;Initial Catalog=MyDatabase;User Id=user;Password=passw0rd"
- $dbProvider = System.Data.SqlClient.SqlClientFactory::Instance;
- $repository = Miado.MiadoRepositoryFactory::CreateMiadoRepository($dbProvider, $connString);
-
- $sql = BuildSql;
-
- foreach ( $row in Import-Csv prices.csv | Select VendorID, FixedPrice, VariablePrice )
- {
- $repository.ExecuteNonQuery($sql.ToString(), $row.VendorID, $row.FixedPrice, $row.VariablePrice);
- }
As you can see, the script iterates over each row in the CSV file and inserts a record for each row. There's no need to write all the code necessary to create the DbConnection and DbCommand objects, nor do you have to dynamically create DbParameter objects for each row. Just pass the SQL and the variables (in order of replacement) into the IMiadoRepository.ExecuteNonQuery() call and Miado takes care of all the ugly details. One line for each insert - that's it! Edit: This post was updated to reflect the changes in the 0.7.10530.1
Wednesday, April 30, 2008 11:38:38 AM (Eastern Standard Time, UTC-05:00) .Net | Miado | Powershell
 Monday, April 14, 2008
New Release of Miado out on CodePlex
I have uploaded a new version of Miado out on CodePlex. I am still calling this a beta. There are a few features I would like to add before I officially proclaim a 1.0 version (ability to use SqlServer-type syntax with an ODBC provider and integrated caching with the IDbStatement are two at the top of my list).
For this latest version, I have moved the DbProvider and vendor specific stuff to the Miado.Configuration namespace. I have added an IParameterParser interface which is used in the SimpleSql class to determine the parameter name declarations in a SQL statement based on whether you are using the ODBC-type syntax or newer syntax for variable declaration.
For example,
MyParam = ?
vs.
MyParam = @MyParam
This week I am going to try and come up with a good set of DAOs that use the AdventureWorks DB so people can see samples of how the API should be used.
Monday, April 14, 2008 6:52:06 AM (Eastern Standard Time, UTC-05:00) .Net | Miado
 Monday, April 07, 2008
 Sunday, April 06, 2008
Miado is out on CodePlex
I have been refining some data access code that I have used on a bunch of my projects to the point where I've made it fairly generic. I decided to publish it as a project on CodePlex. I just put the initial release out today. If you are interested, please take a moment to check it out and give me any feedback. Keep in mind, I wrote this specifically for those people who have (or want) to use straight SQL and ADO.Net in their data access layer. So if you want to use LINQ, Nhibernate, Subsonic, etc... they are absolutely great tools, but they try to hide/remove the SQL from your code, whereas this project just makes it much easier for those who use SQL. Here is an example of how to use it to create a collection of custom business objects: // ideally this declaration would be buried in your base DAO class
// or injected via an IoC container
IDbConfigurable dbConfig = new DbConfiguration(SqlClientFactory.Instance, connString);
IDbStatement dbStmt = new DbStatement(dbConfig);
ICollection<Address> addresses =
dbStmt.LoadSql("SELECT AddressId, Address1, Address2, City, State, ZipCode " +
"FROM Address WHERE City = @City")
.AddParameter("City", "Atlanta")
.QueryForResults<Address>(
row => new Address()
{
AddressId = row.GetValue<int>("AddressId"),
Address1 = row.GetValue<string>("Address1"),
Address2 = row.GetValue<string>("Address2"),
City = row.GetValue<string>("City"),
State = row.GetValue<string>("State"),
ZipCode = row.GetValue<string>("ZipCode")
});
Notice how it removes all the usual boiler plate code from a normal ADO.Net implementation. The only things you really need to do are provide the SQL, set the parameters, and then map the result set to properties on your business object. I'm using lambda expressions in these examples, but if you want to re-use the result set-to business object mappings, I normally create a method in my DAOs to use as a delegate: ICollection<Address> addresses = dbStmt.LoadSql("SELECT AddressId, Address1, Address2, City, State, ZipCode " + "FROM Address WHERE City = @City") .AddParameter("City", "Atlanta") .QueryForResults<Address>(CreateAddress); ... private Address CreateAddress(IResultSetRow row) { // full details not provided return new Address() { AddressId = row.AddressId }; }
If you embed the creation of the IDbStatement interface in a base class (or use the one provided in Miado.Integration), you can see how the code reads even more like a Domain-Specific-Language: // CreateSqlStatment() method is provided in Miado.Integration.MiadoDao
ICollection<Product> products =
this.CreateSqlStatement("SELECT ProductId, Name, Description, Color, Quantity " +
"FROM Product WHERE Color = @Color and Quantity > @Qty")
.AddParameter("Color", "Blue")
.AddParameter("Qty", 20)
.QueryForResults<Product>(
row => new Product()
{
ProductId = row.GetValue<int>("ProductId"),
Name = row.GetValue<string>("Name"),
Description = row.GetValue<string>("Description"),
Color = row.GetValue<string>("Color"),
Quantity = row.GetValue<int>("Quantity")
});
There is also a SimpleSql object that can be used similar to IDbStatement but the syntax is a little more terse since you don't have to map the parameters - they are merely replaced in the order you provide them: IDbConfigurable dbConfig = new DbConfiguration(SqlClientFactory.Instance, connString);
SimpleSql sql = new SimpleSql(dbConfig);
sql.ExecuteNonQuery("UPDATE Person SET FirstName = @FirstName, " +
"LastName = @LastName " +
"WHERE PersonId = @PersonId",
"John", "Smith", 1001);
// again, I like to embed this in a base class so it reads:
// this.CreateSimpleSql().ExecuteNonQuery(sql, param1, param2);
For this first release, SimpleSql is not supported for ODBC SQL statements (since it uses pattern matching to substitute the SQL parameters).
Here's another example where you can see how easy it is to get a count: int count =
this.CreateSimpleSql()
.QueryForOne<int>("SELECT count(*) FROM Employee WHERE YearsOfService > @YearsOfSvc",
new object[] { 15 },
row => row.GetValue<int>(0));
And yes, it supports the creation of DataSets and DataTables: DataSet ds =
this.CreateSimpleSql()
.QueryForDataSet("SELECT * FROM ProductType WHERE Price > @Price", 10.0);
This is the first code drop, so treat it like a beta release.
Sunday, April 06, 2008 9:35:57 AM (Eastern Standard Time, UTC-05:00) .Net | Miado
|

Subscribe to this feed
 Email Me
 Follow Me On Twitter
| | Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|
| 30 | 1 | 2 | 3 | 4 | 5 | 6 | | 7 | 8 | 9 | 10 | 11 | 12 | 13 | | 14 | 15 | 16 | 17 | 18 | 19 | 20 | | 21 | 22 | 23 | 24 | 25 | 26 | 27 | | 28 | 29 | 30 | 31 | 1 | 2 | 3 | | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
Search
Navigation
Tag Cloud
Archive
Blogroll
|