Tuesday, 19 January 2016

Using Kendo Templates

First our template
<script id="data_upload_result_confirmation" type="text/x-kendo-template">
    <h4>#= firstname # is this information correct?</h4>

    <p style="text-align:center;">
        <button class="delete-confirm k-button">Ok</button>
        <a href="javascript:" class="delete-cancel">no</a>
    </p>

</script> 

Then the code to transform the data then open the window
<script>    

  var kendoWindow = $("<div />").kendoWindow({
      title: "Confirm",
      resizable: false,
      width: 550,
      modal: true
  });

  var template = kendo.template(
      $('#data_upload_result_confirmation').html());    
  var data = { firstname: "Rippo" };    
  var result = template(data);


  kendoWindow.data("kendoWindow")
    .content(result)
    .center().open();

</script> 

Wednesday, 6 January 2016

Allowing external urls into your DEV environment

Note to self:

When setting up a new machine (or site) in Visual Studio and you want IIS to server external URL's then open a command prompt with admin privalges and type:-


To delete if it exists
netsh http delete urlacl url=http://dev.wildesoft.net:44300/

To add (notice uppercase E in Everyone)

netsh http add urlacl url=http://dev.wildesoft.net:44300/ user=Everyone

You may need to add the entry in .vs/config/applicationhoist.config

You will also need to open up your routers firewall and also the windows firewall

NOTE: to show list of all allowed URLS
netsh http show urlacl


Tuesday, 13 May 2014

CasperJS Kendo UI Tabstrip

Whilst playing with CasperJS I needed a way to mimic pressing a mouse click on a Kendo tabstrip.

I messed around with all kind of selectors but could not get it to work. Fortunately evaluate came to my rescue.

<div id="tabstrip">
  <ul>
    <li>Lm3 Result</li>
    <li>Results by Location</li>
    <li>Payroll Analysis</li>
    <li>Supplier Analysis</li>
    <li>Supplier Breakdown</li>
    <li>Supplier Locations</li>
  </ul>
</div>



casper.thenOpen("http://localhost:62726/results", function () {
        test.assertTextExists(
           "Analyse different elements", "showing analyse different elements");

        //only way I can see to change a tab strip
        casper.evaluate(function () {
            var tabStrip = $("#tabstrip")
                              .kendoTabStrip()
                              .data("kendoTabStrip");
            tabStrip.select(4);
        });
    });


This utilises JQuery on the page, finds the kendo tabstrip and then selects the 4th tab item.

Wednesday, 11 September 2013

ConvertEmptyStringToNull in MVC

When using MVC and model binding from a form post there comes a time when your database doesn't allow nulls but you find that any empty string from a form post comes back as null. This might be a PITA if you are directly saving the posted form back to the database and don't want to manually convert string null's to empty strings.

The default behaviour of the DefaultModelBinder, is that ConvertEmptyStringToNull is by default, set to true.

To get around this you can add an attribute to your property that guarantees that the binder will not convert the property to an empty string rather than null.

[DisplayFormat(ConvertEmptyStringToNull = false)]
public virtual string Language { get; set; }

Another way is to do it at a global level is to create your own model binder

public class EmptyStringModelBaseBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        bindingContext.ModelMetadata.ConvertEmptyStringToNull = false;

        return base.BindModel(controllerContext, bindingContext);
    }
}
and add your binder in global.asax
ModelBinders.Binders.DefaultBinder = new EmptyStringModelBaseBinder();

Thursday, 22 August 2013

Set the default language for CKEditor and SCAYT

In order to set the DEFAULT language and spell checker in CKEditor when using SCATY (Spell check as you type) you need to add the following in your config values


CKEDITOR.editorConfig = function (config) {
   config.language = 'en-gb';
   config.wsc_lang = "en_GB";
   config.scayt_sLang = 'en_GB';
   config.scayt_autoStartup = true;

   ...
};

Note:-

- the language is en DASH gb (all lower)
- the wsc_lang and scayt_sLang is en UNDERSCORE upper GB

Monday, 19 August 2013

Git and mark as assume-unchanged

I'm working on a small side-project that is on a public GIT repository and there are a few settings that should not be seen or used by other people.

Some settings that I do not want to show are:-

  • Connection strings
  • Meetup API keys

One great way to get around this is two first create the app.config and blank out the values you don't want. Then commit and push to your remote repository. After which key in the following command:-

git update-index --assume-unchanged [fileName]

Git will then stop monitoring changes to that file allowing you to put the real config info into it without fear of checking it in. If you later make changes that you DO want to check in you can run:

git update-index --no-assume-unchanged [fileName]

Lovely!

Thursday, 27 June 2013

Generating a list of which files changed between hg versions

This is more of a note to myself so I can refer to it later!

Every time I want to see a list of changes between two Mecurial revisions I can never remember the correct syntax..

hg status --rev x:y

Where x and y are desired revision numbers...

Wednesday, 16 May 2012

Using DateAdd with NHibernate Linq

The goal is to do something like this using NHibernate and Linq:-
Session.Query<Item>.Where(x => x.Start.AddHours(3) > x.Finish );
If you run this code you will get the following error message:-

[NotSupportedException: System.DateTime AddHours(Double)]

So is there a solution?

The answer is yes, NHibernate is very extensible. The solution below is based on NHibernate 3.3 and the Loquacious configuration.

First you need to create a custom dialect and tell NHibernate about the MsSql `dateadd` function:-
public class CustomDialect : MsSql2008Dialect
{
    public CustomDialect()
    {
        RegisterFunction(
             "AddHours",
             new SQLFunctionTemplate(
                  NHibernateUtil.DateTime,
                  "dateadd(hh,?2,?1)"
                  )
             );
    }
}
Now you need to add the following two classes, the first one extends the DefaultLinqToHqlGeneratorsRegistry and then implement our AddHoursGenerator method.
public class MyLinqtoHqlGeneratorsRegistry : 
    DefaultLinqToHqlGeneratorsRegistry
{
    public MyLinqtoHqlGeneratorsRegistry()
    {
        this.Merge(new AddHoursGenerator());
    }
}

public class AddHoursGenerator : BaseHqlGeneratorForMethod
{
    public AddHoursGenerator()
    {
        SupportedMethods = new[] {
        ReflectionHelper.GetMethodDefinition<DateTime?>(d =>      
                d.Value.AddHours((double)0))
          };
    }

    public override HqlTreeNode BuildHql(MethodInfo method,
      System.Linq.Expressions.Expression targetObject,
      ReadOnlyCollection<System.Linq.Expressions.Expression> arguments,
      HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        return treeBuilder.MethodCall("AddHours",
                visitor.Visit(targetObject).AsExpression(),
                visitor.Visit(arguments[0]).AsExpression()
            );
    }
}
Now all you need to do is to add the CustomDialect to your configuration and tell NHibernate about your custom AddHours generator
var configure = new Configuration()
          .DataBaseIntegration(x => {
              x.Dialect<CustomDialect>();
              x.ConnectionStringName = "db";
          })
          .LinqToHqlGeneratorsRegistry<MyLinqtoHqlGeneratorsRegistry()
          .CurrentSessionContext<WebSessionContext>();
Note: we add .LinqToHqlGeneratorsRegistry<MyLinqtoHqlGeneratorsRegistry()

I have based this on this blog post by fabio.

You can now use your code as is:-
Session.Query<Item>.Where(x => x.Start.AddHours(3) > x.Finish );
This is also possible in 3.2 but the public override HqlTreeNode BuildHql(..) parameters are slightly different...

Tuesday, 8 May 2012

NHibernate 3.3 and medium trust

With the new release of NHibernate 3.3 it seems from my early testing, that the Medium Trust issues have now disappeared and its good to see NHibernate 3.3 works in Medium Trust environments. I need to play with the NH Linq provider more to see what fails but from what I have seen so far I have to congratulate the NH development Team.

As a side note, if anyone is wondering how I test this then please download the modified medium trust file (called policy.config from Rackspace cloud) unzip it and save it to your web root folder.

Next simply add this to your web.config:-
<system.web>
  <securitypolicy>
    <trustlevel name="Custom" policyFile="policy.config" />
  </securityPolicy>
  <trust level="Custom" originUrl="" />
</system.web>
You now have a local development system running under medium trust. For those that do not run Rackspace cloud I would recommend asking your hosting provider for their medium trust policy file.

This is an update from a previous post when using NHibernate 3.2 (September 2011). The JIRA issue can be found here.

Friday, 27 April 2012

Using filters for unmapped columns in NHibernate

Using filters in NHibernate is a little known feature to new users. Filters can be applied in quite few places.

This blog shows us how we can apply a filter onto the class definition:-
<class name="Domain.Model.BlogPost, Domain.Model" table="Posts" 
       where="(IsLive=1)">
    ...
</class>
However be warned this will always return blog posts that are live. Sometimes you may want to get blog posts that are not live. If you use a filter this way then you will never be able to return isLive=0 or ALL blogs regardless of the flag.

Fortunately NHibernate allows us to switch filters on/off at a flick of a switch, add this to your mappings file:-
<filter-def name="BlogFlag">
    <filter-param name=":isLive" type="System.Int"/>
</filter-def>

<class name="Domain.Model.BlogPost, Domain.Model" table="Posts">
  <filter name="BlogFlag" condition="(isLive=:flag)"/>
    ...
</class>
Using the flag could not be simpler, just set the flag before you query:-
//return live blogs
session.EnableFilter("BlogFlag").SetParameter("isLive", 1);
session.QueryOver<MyEntity>();

//return blogs that are not live
session.EnableFilter("BlogFlag").SetParameter("isLive", 0);
session.QueryOver<MyEntity>();

//return all blogs
session.QueryOver&t;MyEntity>();
Now one question you are asking is why would I use filters? Why wouldn't I just use
//Use a where clause! Isn't this more sensible?
session.QueryOver<MyEntity>()
  .Where(w => w.IsLive == isLive);
However one of the unknown undocumented features of filters is that the database column IsLive, DOES not need to mapped to a fully mapped property.

The second reason is that if I ALWAYS want just live Blog posts therefore adding where="(IsLive=1)"> to the class definition makes sense as the developer will does not need to remember to add the where clause for EVERY query.

In the next blog post I will show you how to use filters on collections.

Friday, 20 April 2012

Use a button instead of an anchor tag

When using JQuery and href's we sometimes see the following:-
<a id='MyLink' href="#">My Link</a>
or even worse:-
<a id='ClickMe' href="javascript:void(0);">Click Me</a>
and some jQuery which executes some code, BUT does not redirect the user.
<script>
 $('#ClickMe').click(function(e) {
   e.preventDefault();
   alert('Me clicked');
 });
</script>
Now this works if:-
  1. Javascript is enabled
  2. If JS is disabled then the link should actually should have a fall back, however in this case we don't want to redirect anywhere
  3. Not all browsers support e.preventDefault() so to circumvent this we add a return false at the end of the function
  4. If the page is long; that is longer than the height of the screen then in some browsers the page will jump to the top, losing the Y position

If you think about it these "anchors" exist solely to provide a click event, but do not actually link to other content.

So is there a better solution?

One very nice approach is to convert the anchor tag to a button element.

It can be styled like so:
<button id='Click Me' style="border:none; background:transparent; cursor: pointer;">Click me</button>
the javascript can then be changed to:-
<script>
 $('#ClickMe').click(function(e) {
   alert('Me clicked');
 });
</script>
And of course click events can be attached to buttons without worry of the browser jumping to the top, and without adding extraneous javascript such as onclick="return false;" or event.preventDefault() or even return false.

Tuesday, 17 April 2012

Using QueryOverProjectionBuilder with QueryOver

We all strive to keep our code DRY and sometimes we may have several QueryOver methods that returns the same DTO. This may then lead us to try and create a method that returns a SelectList to reuse in our queries. This gives us the benefit of only changing one method if for example our DTO changes.

First lets look at the QueryOver method. As you can see I have a method call named GetDtoList()
return Session.QueryOver<InvoiceDto>()
    .SelectList(GetDtoList())
    .TransformUsing(Transformers.AliasToBean<InvoiceDto>())
    .List<InvoiceDto>();

Now for the GetList method. As you can see we return a Func of QueryOverProjectionBuilder. In the code we simply build the list as we normally would and just return it:-
Func<QueryOverProjectionBuilder<InvoiceDto>, 
    QueryOverProjectionBuilder<InvoiceDto>> GetDtoList() {
    InvoiceDto dto = null;
    return list => list
      .Select(w => w.ClientName).WithAlias(() => dto.ClientName)
      .Select(w => w.InvoiceDate).WithAlias(() => dto.InvoiceDate)
      .Select(w => w.InvoiceId).WithAlias(() => dto.InvoiceId);
}
Pretty nice I think although the use case for this may be a little limited. The next challenge is to use this when we join to another entity i.e.
return Session.QueryOver<Invoice>()
    .JoinQueryOver<Client>()
    .SelectList(GetDtoList())
    .TransformUsing(Transformers.AliasToBean<InvoiceDto>())
    .List<InvoiceDto>();


Tuesday, 10 April 2012

Using stored procedures with NHibernate

For some reason newbies to NHibernate struggle to find answers on Google or S.O when trying to use Stored Procedures with NHibernate. I have posted this here as a guide to help.

First define in a mapping file that is marked as embedded resource, call it StoredProcs.hbm.xml (the name doesn't matter but the extension .hbm.xml does) :-
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <sql-query name="SummaryReport">
    exec getSummaryReport  :productId
  </sql-query>
</hibernate-mapping>
The stored procedure returns the following SQL columns:-
int ProductId
nvarchar(75) ProductName
decimal(18,2) SalesTotal
bit IsActive 
First we define our c# class:-
public class SummaryReport {
  public virtual int ProductId { get; set; }
  public virtual string ProductName { get; set; }
  public virtual decimal SalesTotal { get; set; }
  public virtual boolen IsActive { get; set; }
}
NOTE: The column names returned from the stored procedure MUST match exactly (case sensitive) the property names on your c# class.

Now for the calling code, as you can see we make use of the method GetNamedQuery and SetResultTransformer:-
var results = Session
  .GetNamedQuery("SummaryReport")
  .SetInt32("productId", productId);
  .SetResultTransformer(
    new AliasToBeanResultTransformer(typeof(SummaryReport)));
return results.List<SummaryReport>();
Note: we call the stored procedure with a parameter :productId. The colon tells NHibernate that this is a parameter. In our calling code we have .SetInt32("productId", productId);, notice that the colon is not required.

Simple isn't it?

Wednesday, 4 April 2012

SetResultTransformer into an anonymous type

The other day I was looking for a way to shortcut the SetResultTransformer and cast a list to an anonymous type rather than having to hand craft DTO classes with public properties (getters/setters). I stumbled on a GitHub Gist by Buthrakaur (Filip Kinský) that did just this.

Why would we want to do this?
  • We may want to return a few columns from an entity
  • We want to return Json from an MVC view which just gets thrown away
  • We want to cut down the amount of code that just handles redundant DTO's because we want to pass data around

The solution to this is really easy (thanks Filip), first we create an anonymous type inline and then project straight into this using an extension method .ListAs(dto)
//first create our anonymous type DTO
var dto = new { 
    Id = 0L, 
    Source = string.Empty, 
    Destination = string.Empty, 
    Is301 = false
};

//notice the ListAs(dto) extension method
var model = Session.QueryOver<CmsRedirect>()
  .SelectList(s => s
    .Select(x => x.Id).WithAlias(() => dto.Id)
    .Select(x => x.Source).WithAlias(() => dto.Source)
    .Select(x => x.Destination).WithAlias(() => dto.Destination)
    .Select(x => x.Do301).WithAlias(() => dto.Is301)
  )
  .Take(take).Skip(page * pageSize)
  .ListAs(dto);

return Json(new { Total = total, List = model }, 
    JsonRequestBehavior.AllowGet);
The source to the GIST can be found here.
public static class NHibernateExtensions {
  public static IList<TRes> ListAs<TRes>(
      this IQueryOver qry, TRes resultByExample) {

    var ctor = typeof(TRes).GetConstructors().First();

    return qry.UnderlyingCriteria
      .SetResultTransformer(
        Transformers.AliasToBeanConstructor(
         (ConstructorInfo) ctor)
        ).List<TRes>();
  }
}
And the Json that gets returned is:-
{
  "Total":3,
  "List":[
    {"Id":101000,"Source":"clients.aspx",
       "Destination":"portfolio","Is301":true},
    {"Id":101101,"Source":"consultancy.aspx",
       "Destination":"consultancy","Is301":true},
    {"Id":101102,"Source":"contact.aspx",
       "Destination":"contact","Is301":true},
  ]
}
This is perfect for plugging straight into my Kendo UI Grid.

A big thank you to Filip for taking some of the repetiveness out of my day.

Sunday, 1 April 2012

QueryOver restriction using an alias

Adding a restriction on a where clause from an alias can be tricky to understand using QueryOver. The SQL we are trying to achieve is:-
from projects p
inner  join user u on p.UserId = u.UserId
where m.UserId = 100 or p.OwnerId = 100
Our goal is to achieve the following:-
  • We have a project that has a owner and a list of managers.
  • Both managers and owners are users
  • We want to get all projects for a user that they are the owner OR the manager
  • We want to use QueryOver
The domain:-
public class User {
    long Id;
    string Name;
}

public class Project {
    long Id;
    User Owner;
    IList<User> Managers;
}
The query is built like this:-
User manager = null;

var query = session
  .QueryOver<Project>()
  .JoinAlias(j => j.Managers, () => manager)
  .Where(w => manager.Id == user1.Id || w.Owner.Id == user1.Id)
  .List<Project>();
The above query joins Project to Managers using an alias manager. This allows us to then use the alias manager in the where statement e.g.
.Where(w => manager.Id == user1.Id || w.Owner.Id == user1.Id)
This works correctly but could have a small glitch. What happens if our domain contains a user that is a owner BUT is not a manager? The problem is the SQL will be created using an inner join. This problem can be fixed by simply adding a LEFT join to the query.
.JoinAlias(j => j.Managers, () => manager).Left
It should be noted that this was an answer I gave to a recent StackOverFlow question.

Thursday, 29 March 2012

Back to the blog

After almost 3 months lay off due to our second son being born (Nico) I have decided to start blogging again (well Nico has decided that I can). He is starting to sleep more through the night and I am now waking up in the morning feeling (almost) refreshed and quite lucid.



I still will be blogging about the .net framework which will include MVC, NHibernate and Simple.Data.

Fingers crossed I can get 4-6 posts out a month and work my way towards 8 posts. If there is anything you want to know then give me a shout!

Thanks for everyones support, Rippo

Tuesday, 13 December 2011

Automatically trim html controls in a asp.net mvc project

I have noticed over the years that users being users sometimes posts forms on a website that has leading or trailing spaces into the input controls. This I find is especially a problem when the user has copied and pasted an email/website address from a internet page or email. On the surface this might be OK but for me especially for email and website addresses when I display this back in a href then sometimes we get:-
- 'mailto:// email@email.com ' or
- href=' http://www.wildesoft.net '

So what I need to remember is to either a) trim before I send to the database or b) trim after I retrieve from the database. I for one prefer option one, better to keep the database correct rather than fixing output in the UI. But is there a way that we can do this for every html control that is posted? With asp.net MVC we can override the default model binder which performs a trim before the value gets to the action method on a controller.

All you need to do is to add the following class to your mvc project:-
public class TrimModelBinder : DefaultModelBinder
{
  protected override void SetProperty(
      ControllerContext controllerContext,
      ModelBindingContext bindingContext,
      PropertyDescriptor propertyDescriptor, object value)
  {
    if (propertyDescriptor.PropertyType == typeof(string))
    {
      var val = (string)value;
      if (!string.IsNullOrEmpty(val))
        val = stringValue.Trim();

      value = val;
    }

    base.SetProperty(controllerContext, bindingContext, 
        propertyDescriptor, value);
  }
}
Then in your application start up method:-
protected void Application_Start() {
  InitContainer();
  ...
  ModelBinders.Binders.DefaultBinder = new TrimModelBinder();
}
Now when a user keys in a leading or trailing space into any input control then the TrimModel binder kicks in and automatically removes it for you.

The only instance where this may be a problem is when a user has a leading or trailing space on their password.

Monday, 5 December 2011

Simple.Data and mysql

To connect Simple.Data to a MySQl database is easiest done via Nuget. NuGet is a Visual Studio extension that makes it easy to install and update open source libraries and tools in Visual Studio.

As of 1st December 20111 the code has been updated to work with version Simple.Data 0.12.2.1

To install via Nuget goto your Package Manager Console window and type:-
PM> Install-Package Simple.Data.Mysql

After installation has been completed then you may need to also install the data connector. As of 1st December the latest version of the connector is 6.4.4

PM> Install-Package Mysql.Data

Please note: You may not need to perform this step as the version of you choice will be loaded dynamically at run time. This dynamic loading means that it's enough that the Mysql.Data.dll file is present in the same directory as Simple.Data.Mysql.Mysql40.dll at runtime. You don't have to take a dependency on the connector if you don't want to.

If all has succeeded then your solution will contain a packages.config file.
<?xml version="1.0" encoding="utf-8"?>
<packages>
 <package id="MySql.Data" version="6.4.4" />
 <package id="Simple.Data.Ado" version="0.12.2.1" />
 <package id="Simple.Data.Core" version="0.12.2.1" />
 <package id="Simple.Data.Mysql" version="0.12.2.1" />
</packages>

Now you are ready to start querying your database.

If you need any help then please direct your questions to the user group.

A big thank you to Vidar Sømme and Richard Hopton who has made all this possible.

Wednesday, 30 November 2011

Simple.Data and bulk inserts

Simple.Data allows you to pass Lists (or IEnumerables) of dynamically or statically typed objects (ExpandoObjects) to the Insert, Update and UpdateBy methods. This is great if you need to perform any kind of bulk insert/update.
var db = Database.OpenNamedConnection("dbConnection");
var list = new List<User>();
for (var i = 0; i < 10; i++)
  list.Add(new User { 
      Id = i + 10000, Username = "User" + i, 
      Password = "Pwd" + i, 
      DateCreated = DateTime.Now.AddDays(-i), 
      RoleId = (i % 3) 
   }
  );
//All users are inserted into the database 
//  with this single call
db.User.Insert(list);
When bulk inserting into SQL Server Simple.Data makes a call to the ADO.NET DbCommand.Prepare() which actually creates a compiled version of the insert statement on the server itself . Then insert statements are then run one by one which should improve performance. However you may not see and performance gain if you are only bulk inserting 2 or 3 rows as there is a small upfront overhead. This compiled temporary stored procedure will be destroyed when the current connection is closed. The SQL profiler shows us:-
declare @p1 int
set @p1=-1
exec sp_prepexec @p1 output,N'
  @p0 int,
  @p1 varchar(50),
  @p2 varchar(50),
  @p3 datetime,@p4 int',
  N'insert into [dbo].[User] ([Id],[Username],[Password],
    [DateCreated],[RoleId]) values (@p0,@p1,@p2,@p3,@p4)',
    @p0=10000,@p1='User0',@p2='Pwd0',
    @p3='Nov 29 2011  8:59:44:897PM',@p4=0
select @p1
and then sends each insert as:-
exec sp_execute 1,@p0=10001,@p1='User1',@p2='Pwd1',
  @p3='Nov 28 2011  8:59:44:897PM',@p4=1
exec sp_execute 1,@p0=10002,@p1='User2',@p2='Pwd2',
  @p3='Nov 27 2011  8:59:44:897PM',@p4=2
exec sp_execute 1,@p0=10003,@p1='User3',@p2='Pwd3',
  @p3='Nov 26 2011  8:59:44:897PM',@p4=0
Note: In the case of Insert you get back a new list of objects with any database-assigned default values such as identity values or timestamps.

The following code is just a check to see that the inserts worked:-
foreach (var item in db.User.All())
  Console.WriteLine(string.Concat(
    item.Id, " ", 
    item.Username, " ", 
    item.Password, " ", 
    item.DateCreated, " ", 
    item.RoleId)
  );

I believe before version 1 release Mark is going to create an Upsert which will either update or insert your entity based on whether the record exists in the database.

Since writng this post, Mark has also done some macro optimisations using Bulk insert which makes use of SqlBulkCopy. Read this blog post to find out more.

Monday, 28 November 2011

Simple.Data Ranges

In this blog I am going to show you how you can use FindAll using ranges that makes use of the BETWEEN operator. The BETWEEN operator (in SQL) is used in a WHERE clause to select a range of data between two values.

Lets look at finding users by Id:-
var db = Database.OpenNamedConnection("dbConnection");
var list = db.User.FindAllById(10002.to(10005));

foreach (var item in list)
  Console.WriteLine(string.Concat(item.Id, " ", item.Username,
    " ", item.Password, " ", item.DateCreated, " ", 
    item.RoleId));
This actually produces the following SQL:-
select
  User.Id,
  User.Username,
  User.Password,
  User.DateCreated,
  User.RoleId
from
  User
WHERE
  User.Id BETWEEN 10002 AND 10005
and returns the following data:-


OK so far so good but what about if we want to get all users that have a RoledId of 1 to 2. This is where the dyanamic features of .net4 and Simple.Data comes alive. All I need to do is change FindAllById to FindAllByRoleId:-
var list = db.User.FindAllByRoleId(1.to(2));

foreach (var item in list)
  Console.WriteLine(string.Concat(item.Id, " ", item.Username,
    " ", item.Password, " ", item.DateCreated, " ", 
    item.RoleId));
The SQL where clause will now be
WHERE User.RoleId BETWEEN 1 AND 2
and returns the following data:-


OK great but what about date ranges?
var list = db.User
  .FindAllByDateCreated("2011-11-20".to("2011-11-22 17:00"));

foreach (var item in list)
  Console.WriteLine(string.Concat(item.Id, " ", item.Username,
    " ", item.Password, " ", item.DateCreated, " ", 
    item.RoleId));
The SQL where clause will now be
WHERE User.DateCreated
  BETWEEN '2011-11-20  00:00:00' 
    AND '2011-11-22  17:00:00'
and returns the following data:-


Great can we also make user of using the BETWEEN operator for strings? you bet:-
var list = db.User.FindAllByUsername("User2".to("User4"));
The SQL where clause will now be
WHERE User.Username BETWEEN 'User2' AND 'User4'

You can also use FindAllBy... range for arrays, this will make use of the IN operator (in SQL) which allows you to specify multiple values in a WHERE clause, more to follow...