Friday, December 10, 2010

WPF Tips and Tricks - DockPanel Doesn't Behave Right

Consider the following:

  1.   <DockPanel>
  2.       <ListBox Width="2000">
  3.         <!-- Lots of items -->
  4.       </ListBox>
  5.       <StackPanel DockPanel.Dock="Bottom" Height="35" Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Right">
  6.           <Button VerticalAlignment="Center" HorizontalAlignment="Right">OK</Button>
  7.           <Button VerticalAlignment="Center" HorizontalAlignment="Right">Cancel</Button>
  8.       </StackPanel>    
  9.     </DockPanel>

You would think that the buttons at the bottom will always be there. But if that ListBox gets too many items, the DockPanel will happily cover up the StackPanel. That doesn't seem right since the StackPanel has an explicit height and it is explicitly docked to the bottom. The reason for this is the DockPanel renders items in the order they are entered. In this case, the ListBox gets rendered first and fills the space. The fix is simple, although does not reflect the real layout of the page. That is to flip the StackPanel and ListBox.

  1.   <DockPanel>
  2.       <StackPanel DockPanel.Dock="Bottom" Height="35" Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Right">
  3.           <Button VerticalAlignment="Center" HorizontalAlignment="Right">OK</Button>
  4.           <Button VerticalAlignment="Center" HorizontalAlignment="Right">Cancel</Button>
  5.       </StackPanel>
  6.       <ListBox Width="2000">
  7.         <!-- Lots of items -->
  8.       </ListBox>
  9.     </DockPanel>

Thursday, September 2, 2010

Making Test SQL Data

Today I had the need to make a lot of dummy rows to test performance of a system. Often the case is when you design a query it performs great with a few thousand rows, but over the years as your data grows, things slow down. So, today I wanted to test my schema with a larger dataset. The first question was how to do that. SQL performs much better with sets, not iterations. The thought of running an INSERT statement millions of times did not appeal to me. Here's some tricks to make a lot of data "relatively" fast.  I say relatively because this will still take many minutes, but not many hours.  Remember, SQL is SET based!  Use sets whenever possible!

-- Don't want 25M "1 Row inserted" messages!
SET nocount ON

-- Some timing stuff, see how fast it is.
        @b DATETIME

SET @a = current_timestamp

-- Create a temporary table to create a multiplier factor.

-- Add 5000 rows to our dummy table.
DECLARE @counter INT

SET @counter = 0
WHILE @counter < 5000
      SET @counter = @counter + 1
      INSERT INTO @myTable VALUES (@counter)

-- This is the big multiplier.. a cartesian product is 5000*5000=25M rows!  We 
-- don't even need to select from the tables, but if we want we could use the
-- numbers for something..
INSERT INTO uw_containers (type_id)
SELECT 1 FROM   @myTable a, @myTable b

-- Now create a history event for each of the new containers.
INSERT INTO uw_container_history

    id,'C' + CAST(id AS varchar(50)),Getdate(),'12/31/9999',139059


SET @b = current_timestamp
SELECT Datediff(ms, @a, @b)

Thursday, August 19, 2010

Known Values and NULL - Communication channels and when to cache

"There are known knowns. These are things we know that we know. There are known unknowns. That is to say, there are things that we now know we don’t know. But there are also unknown unknowns. These are things we do not know we don’t know."  - United States Secretary of Defense Donald Rumsfeld

Rumsfeld really summed up the problem with his statement.  One of the most commonly used constructs in programming in the concept of NULL, to indicate an unknown or unset value.  This is all fine, until you start to design a communication channel and start caching information on the client.  

The problem really comes down to half filled data structures being returned to the client or sent to the server.  This occurs usually because of a trade off between completeness of data and performance or queries.  Now, we can argue whether or not this is the best approach, but for now let's just assume this is the case.  A more valid place for this is an "Update" message to the server, where we want to use a common UpdateRequest structure, but only want to update some portions of the data.

The problem is, when the client sees a NULL in a field, does it mean the value was actually NULL in the database, and therefor a "known unknown" or does it mean the value was never set and therefore the client should request that value from the server if needed?  The same problem can go for updating data:

Say we have the simple UpdateRequest as:
int id;
string name;
string description;

If we send an update request with {id=1, name="Kevin", Description=null}, does that mean that the description is unknown, and should be written as such to the database, or does it mean we don't want to update the description and keep whatever the previous description was?

In order to solve this problem, I introduced a simple wrapper class called KnownValue:

  [DebuggerDisplay("Known: {Value}")]
    public class KnownValue <T> 
        /// <summary>
        /// Initializes a new instance of the <see cref="KnownValue&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="value">The value.</param>
        public KnownValue(T value)
            Value = value;

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>The value.</value>
        public T Value
            get; set; 

The beauty of this simple class is we can now introduce three-state logic:

Description = null: The value is unknown, so don't change it on the server or if the user requests it, we don't have it cached so go get it.
Description = KnownValue<string>(null): The value is known, and should be set to NULL. If the user requests the value, don't go to the server since we already know it is NULL.
Description = KnownValue<string>("My Description"): The value is known, and should be set to "My Description".

Friday, July 2, 2010

What's at a location at a given time?

Today I was challenged with a problem that seemed deceptively simple and the answer is. But coming up with it took a while. The question was for a location log, what were all the objects at a given location at a given time?

The table is simple:
LocationID int
ObjectID int
Date datetime

So, {1,1,6/30/10 10am} would indicate that object 1 was at location 1 at 10am on 6/30/10.

Given a set of log entries:

{1,1,6/30/10 10am}
{2,1,6/30/10 12pm}
{4,1,6/30/10 6pm}
{2,1,6/30/10 8pm}
{1,2,6/30/10 11am}
{3,2,6/30/10 1pm}
{4,2,6/30/10 5pm}

We can see from this list that at 11am for location 1, both object 1 & 2 are there. But at 12:01pm, only object 2 is left. So, how do we get this list for any given time?

Here you go..

declare @myDate datetime
set @myDate='2010-06-30 11:00'
declare @MyLocation int
set @MyLocation =2

select * from
LocationLog t1
left join LocationLog t2 on t1.ObjectID=t2.ObjectID and t2.Date > t1.Date and t2.Date <= @myDate
and t1.LocationID=@MyLocation
and t2.ObjectID is null