Taoffi's blog

prisonniers du temps

Learning from Nature: Towards a 'Nucleotidic' modeling - part I

 

 

 

During several years, I worked on a DNA sequence-analysis software project where I learned about DNA structures and several DNA engineering techniques.

(That is not to be confused with what is commonly called ‘genetic algorithms’ and ‘genetic programming’).

 

Elements and structures used (and manipulated) in molecular biology engineering sphere are fascinating and, above all, source of interesting knowledge. In some way, they define the representation of ‘Life hood’ structures and mechanisms for every living creature (plant, animal, bacteria, virus…)

Molecular biology teaches us that ‘Life’ is based on few nucleotides: A, T, G and C.

Like in music partitions, sequences composed of these few number of nucleotides can give unlimited number of combinations each representing the structure of a specific biological function and, in the end, a specific individual being.

 

Here are some sample (random) fragments of DNA sequences:

 

3’à…GCAATGGTTTCTTACTGTGGAGGACATAAAAATACAGCAAGGGT…à5’

3’à…TTGTGTTGCGAGATGTCGTCGTTAAAGACACTCTTTCTCCCGGAGTCAC…à5’

3’à…CTCTACAGTATAAAGTTCTAGTAAGAGCACAAACTCCTGGACAATTC…à5’

 

Note that DNA sequences are read in a specified direction (noted 3’à5’ in the above sequences).

Nucleotides are considered in complementary (attracted) pairs. A is complementary to T, and G to C.

Each DNA sequence strand has a ‘complementary’ sequence strand where complementary nucleotide pairs are arranged face-to-face in reversed direction to compose part of the well-known helicoidal presentation.

 

Example:

The complementary strand for

3’à…GCAATGGTTTCTTà5’

Is

5’ß…CGTTACCAAAGAAß3’

 

A DNA sequence has its mapped amino acid (protein) sequence. In this mapping, different combinations of three nucleotides (A, T, G or C) compose codons, each mapped to one amino acid (one amino acid may have several codon mappings… see below).

Here are some codon/amino acid mappings:

 

Amino acid

Amino acid Symbol

Codon

Alanine

A

GCA

GCC

GCG

GCT

Arginine

R

AGA

AGG

CGA

CGC

CGG

CGT

Asparagine

N

AAC

AAT

Methionine

M

ATG

 

A sequence may have several “reading frames” in which amino acid codons mapping interpretation may vary. Essentially, to read a sequence, you must first find a starting codon… otherwise; your sequence is the representation of nothing in biological life (real world!)

 

Another interesting aspect is that a specific DNA sequence (with ‘significant’ length) seems to represent one part of a global ‘predefined’ structure… that is, in a way, similar to a known melody in music. If you start to play the first specific notes of, say, a Beatles’ song, everyone can tell the rest of the melody. If your first notes are not specific enough, the result may lead to so many different melodies.

This phenomenon is used in PCR (Polymerase Chain Reaction) in molecular biology engineering to amplify or clone DNA sequences using partial sequences (rigorously selected!).        

 

Useful lessons for software design

Many (if not all J) real world problems seem to follow DNA sequences structure and representations:

§  Basic elements (A, T, G, C)

§  Related each to one another (AT, GC)

§  Composing a global sequence (unique for a specific area)

§  The sequence can be presented differently (DNA /Amino acid)

§  The translation between representations is done through specific mappings (codons / amino acids)

 

PCR technique also seems of great interest to some software areas (OCR recognition for example)

 

I will continue, in future posts, to explore these fascinating structures and propose some applications that mimic and benefit from their behaviors.

 

Back to basics: the Team vs. the Crew!

“If you don’t vent the drain pipe like this, sewage gases will seep-up through the water in the toilet, and the house will stink of shit”!

That seems to be a ‘clear standard’ taught to an apprentice.

Around such clear, understandable and concrete reasoning, you can build a product (or at least a knowledge) that is reusable and sustainable.

In his book “Shop Class As Soul Craft”, Matthew B. Crawford revisits the meaning, structure and alienation of Work and Knowledge in the modern era (particularly after World War II) and delivers a fresh and inspired view of the question.

One of the discussed subjects is the ‘Team’ rhetoric which appears to be the modern form for trying to definitively remove the individual from the image of ‘Work’.

 

“There is a sort of friendship or solidarity that becomes possible at work when people are open about differences of rank, and [where] there are clear standards.”

 

Throw, but only ‘exceptional’ exceptions!

I find the Try/Catch mechanism fascinating! This is probably due to some events I lived in the (not so far) History! (see below)

The thing is, when I see any of its related keywords: try, catch, finally and, specially, throw… I feel some kind of nervousness or unease!

Unfortunately, for me, more and more source code tries, catches and throws exceptions. It seems sometimes easier to throw an exception while simply an object ‘status’ would be required.

Some history

I remember an intriguing piece of code (2 or 3 C language macros) that was one of the first research I encountered about implementing a dynamic error capturing (now called ‘exception handling’). I kept this code for years (in my ‘code-museum’!) but ended up by losing it through the long journey of OS, compilers and IDEs changes!

Fortunately, I found someone (Francesco Nidito) who still (beautifully) talks about this nearly same macros (you can have a more detailed look here). His article is exactly about the solution that I first saw in the 80s, with some interesting additions (mixed with a good dose of humorJ).

 

If you used C language before, you know the impact (and importance) of ‘preprocessing’. This is the step where the compiler expands the expressions before going further in the compilation process.

For example, if you define a macro:

 

#define SAY_HELLO   int    x;\

                    for( x = 0; x < 10; x++)\

                           printf(“Hello!”);

 

In the preprocessing step, the compiler will replace each SAY_HELLO occurrence by the lines of code above.

 

longjmp And setjmp

Before diving in the historical macros, to better understand their work, we should first have a look at those two (strange) C language functions: longjmp and setjmp (declared in setjmp.h header file):

 

int setjmp(jmp_buf env);

void longjmp(jmp_buf env, int val);

 

The documentation says:

 

The setjmp function saves a stack environment, which you can subsequently restore, using longjmp. When used together, setjmp and longjmp provide a way to execute a non-local goto. They are typically used to pass execution control to error-handling or recovery code in a previously called routine without using the normal calling or return conventions.

A call to setjmp saves the current stack environment in env. A subsequent call to longjmp restores the saved environment and returns control to the point just after the corresponding setjmp call. All variables (except register variables) accessible to the routine receiving control contain the values they had when longjmp was called.

It is not possible to use setjmp to jump from native to managed code.

Note   setjmp and longjmp do not support C++ object semantics. In C++ programs, use the C++ exception-handling mechanism.

The basic Try/Catch macros

Using the magic that can be done by setjmp and longjmp, the following bizarre macros are the basis of a try/catch mechanism:

 

#define TRY            do{ jmp_buf ex_buf__; if( !setjmp(ex_buf__) ){

#define CATCH          } else {

#define ETRY           } }     while(0)

#define THROW          longjmp(ex_buf__, 1)

 

So, now you may write

 

TRY

{

       DoSomething(“with this string”);

}

CATCH

{

       printf(“some error happened!”);

}

ETRY         /* end of try/catch! */

 

At compile-time, this would be expanded to the following code:

 

do{ jmp_buf ex_buf__; if( !setjmp(ex_buf__) ){

{

       DoSomething(“with this string”);

}

} else {

{

       printf(“some error happened!”);

}

} }   while(0)           /* end of try/catch! */

 

 

What does it mean?

Let’s try to read the macros meaning:

TRY, ends with an ETRY. That is do{ xxxx } while(0) (which means: do xxxx only ONCE)

TRY starts by saving the current caller’s stack into a ‘jmp_buf’ variable. If saving the current caller stack succeeds, the next instructions (code block of ‘try’) are executed. Otherwise, the catch block instructions are executed instead.

THROW executes a non-local GOTO (by calling longjmp) which returns execution to the previous caller of the stack saved into the jmp_buf with a return value of 1 (of course, longjmp can be called with a different return value).

 

Anything new?

Of course, our C++, C# and VB Try/Catch mechanism is a little more elaborate than the one exposed here. The foundations remain the same. And, in fact, nothing had fundamentally changed in this area since: any try/catch block executes, at least, this fearful acrobatic setjmp / longjmp.

 

It may be useful to remember this before writing your next try/catch block!

 

Windows Vista / Windows 7: To pin or not to pin, that is…

Have you ever tried, in Windows Vista or 7, to pin to the start menu (or to the task bar), an item whose name contains ‘documentation’?

Well, that is simply impossible (and, above all, forbidden!)

(You may have a look at this discussion… hope the link will still be aliveJ)

 

Why?... and Who decided this?

 

Why?

In Windows Vista or 7, you cannot pin to the start menu (nor to the task bar), any item whose name contains one of the following words (quite long list... long list J):

·         Documentation

·         Help

·         Install

·         More Info

·         Read me

·         Read First

·         Readme

·         Remove

·         Setup

·         Support

·         What's New

 

Note that this doesn’t still tell us any useful information about WHY are these words excluded from ‘pinnable’ items. And what logic is behind this choice?!

Nobody and no literature want to explain something plausible about this mysterious choice.

 

Still you can do It!

Curiously enough, you can still pin an item whose name contains one of these blasphemed words. Without even going to the famous ‘Registry’, just try the following:

·         Rename your item to be pinned (example: remove just one character of ‘documentation’ to obtain something like ‘documentatio’);

·         You can now pin your item to whatever you want;

·         Rename again the item to its original name;

·         Rename the pinned item to the name you like.

 

Who?

As for ‘Who’ decided and designed this genius (customs-office-attitude-like) feature?... It seems that those are the same Microsoft’s young people playing with Windows Interface, under the name of “Application User Model ID” to deliver us some awesome features (like sub folders hysterically bouncing down when you expand them: see this post).

They, apparently, continue to care about us in Windows 7

God bless them all… hope they will still be there in Windows 8.

 

Is it a shame?

As you may have noticed, the link to http://support.microsoft.com/kb/282066... The page where this design is confirmed doesn’t exist anymore!

 

Sorting dates: Ascending, Descending OR…

This is a small story, yet with something special:

Once upon a time, there was a list of events stored into a database table. Each event had (evidenceJ) a date.

A friend of mine asked me to sort these event items.

I asked, as you may imagine: Ascending or Descending?

 

But this, apparently, seemed too simplistic for him…

- I want the most recent to appear first. He said.

- Well, that means you want to sort in descending order.

I gave him a demo of data sorted in descending order…

- No, he said, that is not what I want!

 

After a short discussion, I understood that what he wanted was:

·         To first have the incoming events (i.e. those located after “today’s” date… sorted in an ascending order)

·         Followed by older dates (sorted in ascending order)

 

I first thought: can ORDER BY do something else than sorting in ascending / descending?...

As the answer was, evidently, No… I said: Sorry, but that is not possible!

The question remained in my mind however. And I started looking for a solution (for myself!)

The experimentations didn’t in fact last long, the solution was quickly found:

 

All what we need is to:

§  Categorize dates according to their location relative to Today (or any other logic);

§  Give each category a ‘sortable’ value (integer for example)

§  Sort by the category’s value, followed by the date value.

 

Example:

SELECT TOP (100) PERCENT

      event_date,

      description,

      CASE WHEN event_date >= getutcdate() THEN 1

            ELSE 2

      END               AS date_category  -- categorize date

FROM         dbo.sight_conferences

ORDER BY date_category, event_date

 

 

Screenshot of the output data sample

 

 

 

The key part of this code is the logic of categorizing dates. In this sample, categorization was quite simple (set a category according to date location relative to Today). But, of course, we can use another logic scheme to obtain data sorted accordingly.

Organize your MSDN Help Favorites

If you regularly use MSDN help (Visual Studio Documentation or MSSQL Server Books OnLine (BOL)) you may have noticed that it is not possible to sort or search the list of help favorites.

Migrating these favorites to another machine is almost more painful!

I suffered from these problems for a long time, until I decided to write a tool to help resolving these lacks.

What does the tool do?

HelpFavoriteOrganizer can locate and read your Favorites (xml) file (for Visual Studio or MSSQL documentation) and allow you to sort and search favorite topics. It also locates duplicated topics (i.e. topic having the same help addresses)

You can then save you favorite file, to either a new xml file or overwriting the original XML favorite file.

Another useful feature is to import (merge) an existing xml favorite file into your favorite topics. This can allow an easier roaming life, and can also be used to share your help favorites with someone else.

 

ATTENTION: be careful when deleting items or overwriting files because this tool DOES NOT ask any confirmation. (i.e. use it at your own risk!)

That said (!), you can download it Here: HelpFavoritesOrganizer.zip (34.82 kb)

Some screen captures

Try to locate and load either VStudio help or SQL help favorites

 

 

 

 

.

Sort / Search your topics… items highlighted

Save the list either to a new file or to the original help favorites file.

 

.

Locate / delete duplicated topics (As you can see, I have no more duplicatesJ)

 

.

Import (merge) another favorites xml file

 

Managing databases periodic membership (or: unique time span indexing) Part II

Ho to view periodic relationship data

In the previous post, I exposed a method for uniquely indexing time spans of periodic-memberships.

 

Here, we will discuss the next task: How to view historical data in such structures?

To illustrate this, we will talk about a portfolio sample data, simply because this is a more elaborate case (than the hotel/room reservation case).

 

Suppose we have:

§  A portfolio named ‘Sample portfolio’

§  A set of companies: company 1, company 2 and company 3

§  A set of daily historical data for each company for the period from 2010/01/01 to 2010/01/10

 

Now suppose that:

§  Company 1 and company 3 are ‘permanent members’ of the portfolio starting at 2010/01/01

§  Company 2 is a member of the portfolio for the following periods:

o   2010/01/01 to 2010/01/05

o   2010/01/08 to à endless

 

To query the daily historical data for company 2 related to its parent portfolio, we should thus obtain the data for the periods where it is effectively a member of the portfolio:

§  2010/01/01, 2010/01/02, 2010/01/03, 2010/01/04, 2010/01/05

§  2010/01/08, 2010/01/09 and 2010/01/10

 

(Note that data for 2010/01/06 and 2010/01/07 should be ignored)

 

This can be done using a view similar to the following (TSQL followed by the view design diagram)

 

SELECT     p.name AS portfolio,

                c.name    AS company,

                history.date,

                history.data

 

FROM dbo.portfolio_companies AS pc INNER JOIN

                      dbo.portfolios AS p ON pc.portfolio_id = p.id INNER JOIN

                      dbo.company_data AS history

                ON pc.date_start <= history.date

                               AND ISNULL(pc.date_end, CONVERT(datetime, '9999/01/01')) >= history.date INNER JOIN

                      dbo.companies AS c ON history.company_id = c.id AND pc.company_id = c.id

 

As said above, company 2 is a portfolio member during the following periods:

§  2010/01/01 to 2010/01/05

§  2010/01/08 to à endless

 

 

 

With our sample history data, this view produces the following data for company 2 (8 entries):

 

 

Note: the history data table contains the following data for company 2 (10 entries):

 

 

Managing databases periodic membership (or: unique time span indexing)

Introduction

The relations between some ‘real world’ objects can sometimes be in the form of ‘periodic membership’. By ‘periodic membership’, I mean the context when one object can be member of another during one or more periods of time.

Examples:

·         A person who occupies a hotel room during a period of time;

·         A company which is member of a portfolio during a period of time;

·         … etc.

 

The context also assumes that we want to keep the membership history and be able to build data aggregations that take into account these periodic memberships. (For example: be able to calculate portfolio performance during a period of time that spans several ‘periodic memberships’).

 

A concrete example may better explain the case:

§  We have a portfolio for which we want to maintain historical performance during time;

§  At 2009/01/01, the portfolio contained : company1, company2 and company3;

§  At 2009/03/01, we changed the portfolio components and excluded company2. (Now the portfolio contains only company1 and company3);

§  At 2009/06/01, to calculate the portfolio performance for the period 2009/01/01 to 2009/06/01, we should take company2 into account for the period 2009/01/01 to 2009/03/01 (although it is no more part of the portfolio).

 

Knowing that database engines do not offer a ‘time-overlap’ unique indexing features, resolving this situation needs a structure that allows us to assign and manage periodic membership indexes.

Note: I am surely not the first to confront this context, but I wanted to share my experience to resolve this problem and will be glad to receive any thoughts about it.

 

Periodic membership multiplicity models

In my experience, I encountered two possible types of multiplicities related to periodic relationship:

§  One-to-one periodic membership: a good example for this would be a hotel room that can be occupied only by one person during the same period (i.e. period is unique per room);

§  One-to-many periodic membership: a good example for this would be a portfolio which can have more than one member for the same period (i.e. period is unique per portfolio-member).

In this article, I will explain how to handle both of these types.

 

Hotel room reservation, the basic structure

To demonstrate a hotel reservation periodic membership (uniqueness of room/reservation period), we can create the following table and relationships:

 

§  Hotel clients: contains client list items

§  Hotel rooms: contains room list

§  Hotel room reservations: contains client/room reservation periods

 

Note: the date_end field of the reservations table can be null, to allow ‘permanent’ (or endless) reservations.

 

To ensure uniqueness of reservation periods, we will create a scalar function (returning a Boolean value) that can be used as Check Constraint on the hotel_room_reservations.

 

CREATE FUNCTION [dbo].[is_valid_hotel_reservation_period]

(

       @item_id     int,

       @room_id     int,

       @date_start  datetime,

       @date_end    datetime

)

RETURNS bit

AS

BEGIN

       -- validate the provided parameters    

       if @date_start is null or @room_id is null

             return 0

 

       -- be sure start date < end date 

       if not @date_end is null

       begin

             if @date_start >= @date_end

                    return 0

       end

      

       -- is this the first reservation period for this room?

       if ( select count(*)

                    from dbo.hotel_room_reservations

                    where( room_id = @room_id) ) <= 0

             return 1

      

       -- check overlapped periods

       if @date_end is null              -- is this a permanent (endless) reservattion?

       begin

             if ( select  count(*)

                    from dbo.hotel_room_reservations

                    where( ( room_id = @room_id)

                                  and( id != @item_id)

                                  and(( date_end is null) or (date_end >= @date_start))

                           )) > 0

                    return 0

       end

       else

       begin

             if ( select  count(*)

                    from dbo.hotel_room_reservations

                    where(       (room_id = @room_id)

                                  and( id != @item_id)

                                  and( date_start <= @date_end)

                                  and(( date_end is null) or (date_end >= @date_start))

                           )) > 0

                    return 0

       end

      

 

       -- return OK

       return 1

END

 

We can now use this function as check constraint on the reservation table:

 

 

Overlapping entries in the reservation table would now display an error message like:

The Portfolio/company periodic membership case

In portfolio/company case, membership should allow multiple membership instances for different periods. That is: the same company can be member of the same portfolio several times as long as the membership periods do NOT overlap.

 

Our tables and relationships may look like the following:

 

All what we need is to create a new version of the above function, and use it as a check constraint condition for the portfolio companies table:

 

CREATE FUNCTION [dbo].[is_valid_portfolio_company_period]

(

       @item_id     int,

       @portfolio_id int,

       @company_id  int,

       @date_start  datetime,

       @date_end    datetime

)

RETURNS bit

AS

BEGIN

       -- validate the provided parameters    

       if @company_id is null or @date_start is null or @portfolio_id is null

             return 0

 

       -- be sure start date < end date 

       if not @date_end is null

       begin

             if @date_start >= @date_end

                    return 0

       end

      

       -- is this the first membership period for the portfolio/company?

       if ( select count(*)

                    from dbo.portfolio_companies

                    where( portfolio_id = @portfolio_id)

                           and( company_id = @company_id) ) <= 0

             return 1

      

       -- check overlapped periods

       if @date_end is null              -- is this a permanent (endless) membership?

       begin

             if ( select  count(*)

                    from dbo.portfolio_companies

                    where( company_id = @company_id

                           and( portfolio_id = @portfolio_id)

                           and( id != @item_id)

                           and(( date_end is null) or (date_end >= @date_start))

                           )) > 0

                    return 0

       end

       else

       begin

             if ( select  count(*)

                    from dbo.portfolio_companies

                    where( company_id = @company_id

                           and( portfolio_id = @portfolio_id)

                           and( id != @item_id)

                           and( date_start <= @date_end)

                           and(( date_end is null) or (date_end >= @date_start))

                           )) > 0

                    return 0

       end

      

       return 1

END

 

We can, now, use the function as a check constraint condition for the membership table:

 

 

Possible extensions

It seems that, with some more efforts, this can evolve to a generic Time-Span unique indexer.

Waiting to hear some thoughts about thisJ!

Silverlight database to DataGrid, yet another approach- Part V

The data record (the ‘form’)

As I mentioned in Part II, my proposed solution (aimed to transfer and communicate data between a Silverlight Client and the database server) is composed of the following schematic classes:

Data level classes

SilverDataTable

Represents the table (or view, or function…) data.

Contains:

A meta-data table

A list of data rows

SilverDataRow

Represents one record of data.

Contains:

List of data cells

Linked to:

A parent table

SilverDataCell

Represents one record’s data cell.

Linked to:

A parent row

A parent meta-data column

Meta-data level classes

SilverMetaTable

Represents the table’s meta-data (schema)

Contains:

A list of meta-data columns

Linked to:

A parent table

SilverMetaColumn

Represents one column’s schema information.

Note: This is the ‘Key Class’ where you can insert all your required business logic.

Linked to:

A parent meta-data table

 

The SilverMetaColumn class is the key class which will transport many of business logic information from the database server to the client (and back to the server).

A meta-data column object of this class can transport information like:

§  The column’s data type;

§  Can the column contain null value?

§  The semantic type of the field (ex: control type… i.e. is this an option list? a value entry field?…)

§  Valid value ranges;

§ 

§  etc.

 

What I want to expose here is: how to use this meta-data column object to ‘automatically’ (or semi-automatically) compose a data record (form) on the client side.

 

From the field semantic àto the control àto the form

After having examined many of the data entry forms in various contexts, I think that a data entry (from the user interface point of view) is either:

§  A value entry control (i.e. a TextBox or TextBox-like: Numeric Up-down control for example)

§  Or a choice control (i.e. a ListBox, ComboBox, CheckBox, Radio-buttons-collection or other type of collection container controls)

 

Of course, the visual aspect of the control and its interactivity scenario may vary… but its presentation-semantic remains the same: a value entry or a choice.

From the business logic point of view (at the server side), what is important is not the visual aspect or visual transitions for presenting and collecting the data. What is important is the conformance of the collected data to specific business logic constraints:

§  Does the entry conform to the required data type?

§  Does the entry conform to the required valid range?

§ 

 

According to this approach, we can imagine a solution where the server tells the client:

§  Here is the requested data record composed of:

§  Column 1 : this is the record key column, It is Read-only (i.e. it will be handled at the server)

§  Column 2: this is an entry of data type Text, Required (cannot be null), cannot exceed 50 characters, Current value is “sample entry”;

§  Column 3: this is an entry of data type integer, Can be null, Valid range is 0 through 40, Default is 25, Current value is 32;

§  Column 4: this a single choice of the following option list (x1, x2, x3), Cannot be null, Current value is x2;

§  Column 5: this a boolean value, default is True, Current value is False;

§ 

 

Receiving this information, the client can then undertake the presentation process, for example:

§  Start record presentation transition (animation);

§  For each column, create the corresponding control (ex: according to the user interface graphical chart);

§  Set each control’s properties to conform to business constraints (read-only, max chars, valid values check… etc.)

 

Here is an example of a solution using this approach:

 

Silverlight database to DataGrid, yet another approach- Part IV

Filtering database data

As we have seen in Part III, the SQL Select statement is composed of the following parts:

SELECT                 [field1], [field2],… [fieldn]

FROM                   [database table or ‘table-like’ store]

WHERE                [conditions]

ORDER BY           [field name] <sort direction>,

                               [field name] <sort direction>

 

It is the ‘WHERE’ clause of the SQL statement that is used to filter the data.

‘WHERE’ is followed by ‘conditions’. Several conditions are concatenated using AND or OR operator.

What is a filter condition?

A ‘condition item’ can be presented as:

[Field name] [Comparison operator] [Filter value]

 

A collection of ‘condition items’ can be presented as something like:

<Condition item> <Concatenation operator> <Other condition item>

 

Examples:

Name = ‘John’

Amount >= 100

(Last_name LIKE ‘%bama’) AND (Age >= 20)

 

That seems easy to be represented by an object:

public class SilverFiltertItem

{

       string              m_field_name,

                           m_filter_value;

       CompareOperator     m_compare_operator  = CompareOperator.EQUAL;

       ConcatOperator      m_concat_operator   = ConcatOperator.AND;

       ...

       ...

The concatenation and comparison operators are members of the following enum types:

public enum filter_concat_operator

{

       and,

       or,

       none

};

 

public enum filter_compare_operator

{

       Equal,

       Not_equal,

       Like,

 

       GreatertThan,

       GreatertThanOrEqual,

       LessThan,

       LessThanOrEqual

       ...

       ...

};

 

Two properties can give us the Compare and Concatenate strings when required:

protected string ConcatString

{

       get

       {

             if( m_concat_opertaor == filter_concat_operator.none)

                    return "";

 

             // return ‘AND’ or ‘OR’

             return Enum.GetName( typeof( filter_concat_operator), m_concat_opertaor).ToUpper();

       }

}

 

protected string CompareString

{

       get

       {

             switch (m_compare_operator)

             {

                    case filter_compare_operator.Equal:

                           return "=";

 

                    case filter_compare_operator.Like:

                           return " Like ";

 

                    case filter_compare_operator.Not_equal:

                           return "!=";

 

                    case filter_compare_operator.GreatertThan:

                           return ">";

 

                    case filter_compare_operator.GreatertThanOrEqual:

                           return ">=";

 

                    case filter_compare_operator.LessThan:

                           return "<";

 

                    case filter_compare_operator.LessThanOrEqual:

                           return "<=";

 

                    default:

                           throw new Exception("Unknown Compare opertor encoutered!");

             }

       }

}

 

The FilterItem object can now provide us with its SQL string through a property like the following:

public string SqlFilterString

{

       get

       {

             if( string.IsNullOrEmpty(m_filter_value)

                           || string.IsNullOrEmpty( m_target_column_name))

                    return "";

 

             string       field_name   = "[" + m_target_column_name + "]",

                          str_ret      = ConcatString + "(";

 

             string str_value    = m_filter_value;

            

             str_ret      += field_name + " " + CompareString + " " + str_value + ") ";

             return str_ret;

       }

 

A filter collection class may look like this:

public class SilverFilter : List<SilverFilterItem>

{

       ...

       ...

 

The filter collection can return the entire SQL filter string through successive calls to its member items:

public string SqlFilterString

{

       get

       {

             if( Count <= 0)

                    return "";

 

             int    ndx          = 0;

             string str_ret      = "";

 

             foreach (SilverFilterItem f in this)

             {

                    if (ndx <= 0)

                           f.Concat_operator = filter_concat_operator.none;

                    else

                    {

                           if( f.Concat_operator == filter_concat_operator.none)

                                  f.Concat_operator   = filter_concat_operator.and;

                    }

 

                    str_ret      += f.SqlFilterString;

                    ndx++;

             }

 

             return str_ret;

       }

 

 

Our DataTable object (see previous posts) can now include a Filter collection object and construct the SQL Where clause:

 

protected SilverFilter    m_filter     = new SilverFilter();

...

...

 

public string SqlCommand

{

       get

       {

             ...

             ...

             string       str_cmd      = "SELECT * FROM " + m_table_name;

             string       str_sort     = m_sort.StrSql;

             string       str_filter   = m_filter.SqlFilterString;

 

             if( ! string.IsNullOrEmpty( str_filter))

                    str_cmd      += " WHERE(" + str_filter + ")";

 

             if( ! string.IsNullOrEmpty( str_sort))

                    str_cmd      += " ORDER BY " + str_sort;

 

             return str_cmd;

       }

 

Note: a better approach would, of course, be to map the filter field names to the table’s meta-data table fields… or directly use MetaDataTable’s columns as filter members (instead of using field names as strings). In this last case, we would be able to check columns’ data types and also act more closely to database’s business logic.

 

In other words: what is proposed here is a simple approach that can evolve according to your needs.

 

 

You can download the sample code: SilverDbDataGrid-2-sorting&filtering.zip (1.87 mb)