Monday, November 29, 2010

Linq to NHibernate: no data layer!

NHibernate 3 includes Linq. These two combined makes your datalayer 'dissapear'. In the following example I'll show you how to set up your entities in a way you can reference them from your code without any knowledge of the underlying database and database model.
I will give this example with the widely known Northwind database.

On the right a picture shows an outline of the project. NortwindEntities is a .NET 3.5 Class library with references to NHibernate 3.

There are two folders: one containing the entities (objects), and one containing the mapping files used by NHibernate to map the entities-logic to the relational database. The final file is called NortwindContext.cs. This file contains functionality to setup a SessionFactory and a Session. The depended file (actually a partial class) NortwindContext.Entities.cs holds properties to access the entities of the context in a proper way. For example in Linq to NHibernate the Customer entity is referenced as:


session.Query<Customer>();

The NorthwindContext has a property Customers:

public IQueryable<Customers> Customers
{
get { return Session.Query<Customers>(); }
}

Setting up this Class library is the difficult part. But when it is done, you can reference it from your application. With two lines of code you have set up the Context (including the connection to the database)



// Set up the servername once
NorthwindContext.SetSQLServer(".\\SQLExpress");
// Create a new context
var nc = new NorthwindContext(true);

Retrieving your entities is as simple as:



var customers = nc.Customers.Select(c =>
new { c.ContactName, c.Orders.Count });

Saving your entities isn't that hard anymore:



var customer = new Customer
{
Id = "FOE",
ContactName = "Frank",
City = "Dalem"
};
nc.SaveOrUpdate(customer);
nc.Flush();

Conclusion: The datalayer kind of dissapeared.


You can download the example solution here. It also includes the SQL-script to generate the Northwind database in your SQL Server (express) enviroment.

Friday, November 05, 2010

Client side confirmation in asp:CommandField

When you have an asp.net gridview (framework 3.5) on your page, which includes a column of "asp:CommandField" there is no option to control any client-side behaviour with the designer. I wanted a client side confirmation when a user pressed the delete icon which I placed by asp:CommandField ButtonType="Image" DeleteImageUrl="~/images/del.png" ...

There is a way to add client side confirmation to the asp:CommandField delete action. This is done by injecting javascript into the generated ImageButton in the OnRowDataBound event of the gridview. In the example below, the code loops through all the controls in the last cell of the row (there is where I have the asp:CommandField). If the control is an ImageButton and it has the CommandName "Delete" then set the OnClientClick property to a javascript call.


protected void grdItems_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.Cells.Count > 1)
{
var ctls = e.Row.Cells[e.Row.Cells.Count - 1].Controls;

foreach (var c in ctls)
if ((c is ImageButton)
&& (((ImageButton)c).CommandName == "Delete"))
((ImageButton)c).OnClientClick =
"if (!window.confirm('Are you sure')) return false;";
}
}

Thursday, September 23, 2010

Aggregate string with Linq

Linq gives you the standard aggregate function like sum, average, max, etc. But if you want (for some reason) want to concatenate some string-values in a group by it is not possible with a build-in operator.

The following code shows an example of how to group a list of values and aggregate a list of strings to a comma separated line with unique values.



var orderList = new List();
var c = new Customer { Name = "Frank" };
orderList.Add(new Order {Customer = c, Amount = 2, Price = 1.99 } );
orderList.Add(new Order {Customer = c, Amount = 4, Price = 1.59, Note = "Discrete" } );
orderList.Add(new Order {Customer = c, Amount = 1, Price = 21.00 } );
orderList.Add(new Order {Customer = c, Amount = 80, Price = 0.99, Note = "Before Xmas!!" } );

c = new Customer { Name = "John" };
orderList.Add(new Order {Customer = c, Amount = 9, Price = 1.99 } );
orderList.Add(new Order {Customer = c, Amount = 14, Price = 2.59, Note = "Call when send" } );
orderList.Add(new Order {Customer = c, Amount = 7, Price = 26.95 } );
orderList.Add(new Order {Customer = c, Amount = 90, Price = 0.99 } );

var q = orderList
.GroupBy(order => new { order.Customer.Name },
(customer, orders) => new {
customer.Name,
Totalprice = orders.Sum(o => o.Price),
Notes = string.Join(", ", orders
.Where(o => string.IsNullOrEmpty(o.Note) == false)
.Select(o => o.Note).Distinct().ToArray())
});

q.Dump();

Linqpad will give this output:



Friday, May 07, 2010

SQLite and .NET 4.0

When I converted an existing C# solution with NHibernate/SQLite to .NET 4, I got the following runtime exception:
Could not create the driver from NHibernate.Driver.SQLite20Driver, NHibernate, Version=2.1.2.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4.

The cause is that the System.Data.SQLite.dll is compiled against .NET 2. To avoid this problem, you can add te following configuration in your app.config:



and the application runs fine.

Thursday, May 06, 2010

MapXtreme hide legend items

In some cases you do not want certain features shown in your legend of a map.

Setting the property of Thematics.IndividualValueTheme.Bins(0).LegendRow.Visible to false will not work in MapXtreme 6.8.
This is a known bug and there is no patch.
However when you create a ThemeLegendFrame based on this IndividualValueTheme you can hide items from the legend by
Legends.ThemeLegendFrame.Rows(0).Visible = false