alkampfer on March 9th, 2010

I have this piece of domain model.

image

The LinkResult class has a property called Link that point to a AnalyzedLink class that in turn has a collection of AnalyzedLinkExtClass called ExtData. All the relation are unidirectional, this means that there is nothing that bring me from AnalyzedLink to a linkResult and nothing that bring me from AnalyzedLinkExtData to the AnalyzedLink. This is the typical situation where doing complex query can be tricky

Now I had to find all the LinkResult objects that have Status = LinkResultStatus.Ok and the associated AnalyzedLink must not contain an AnalyzedLinkExtData with the property Source equal to a certain value.

The query in HQL is

   1: @"select L 

   2: from LinkResult L 

   3: join L.Link AL 

   4: where L.Status = :status and 

   5: not exists (from AL.ExtData ED where ED.Source = :source) 

   6: order by L.AnalysisDate desc"

This is really powerful, I can simply start the query from the LinkResult object, then join to the L.Link and set a condition on L.Status property.

Now I add a not exists with the condition (from AL.ExtData ED where ED.Source = :source) as you can see I do not need to specify any join, but I can select directly from the ExtData Collection Property of the AnalyzedLink result. The SQL generated is

   1: select

   2:        linkresult0_.Id as Id175_,

   3:        .....

   4:    from

   5:         LinkResult linkresult0_ 

   6:     inner join

   7:         AnalyzedLink analyzedli1_ 

   8:     on linkresult0_.link_id=analyzedli1_.link_id 

   9:     where

  10:         linkresult0_.status=@p0 

  11:         and  not (exists (select

  12:             extdata2_.aled_id 

  13:         from

  14:             AnalyzedLinksExtData extdata2_ 

  15:         where

  16:             analyzedli1_.link_id=extdata2_.aled_link_id 

  17:             and extdata2_.aled_source=@p1)) 

  18:     order by

  19:         linkresult0_.analysisDate desc;

The real magic is done in the subquery, because you can verify that the condition on subquery contains two condition, the first is the link with the outer query, and the second one is the one we put on HQL. But you can surely appreciate the fact that in HQL the query is really clearer and shorter :)

alk.

Tags:



kick it on DotNetKicks.com

Tags: ,

alkampfer on March 5th, 2010

I have a project with a complex user control used to select some values in hierarchic categories, it was realized with the UpdatePanel, it supports searching, selection by cascade of combo and much more, everything works great, but performances are not so good.

Now I decide to create another version that use jQuery to do real ajax calls and manage json data to maximize performances, but I face a problem

  • I need to create a UserControl.
  • I can have more than one instance of this user control in a single page (but I want a single jquery script)
  • The user want to move the focus on a specific part of my control when the popup opens.

This is an interesting problem, because the popup logic is done with the PopupControlExtender and I do not want to change it. My goal is to be able to execute some jQuery code when the popup appears and move the focus on a control contained in the popup. Since Microsoft Ajax library, used by the PCE, creates a client side javascript object for each PopupControlExtender, my first problem is “how can I select the javascript object that correspond to my server side control, when I can have more than one instance of the user control in the page (this means multiple PCE)?

If you know the microsoft ajax library you already know the $find() function, and you should know also that you can use a particular property called BehaviorID to give a unique Id to the client part of a component. A partial solution to my problem can be found here (look in the end of the post). In that post the PopupControlExtender was declared in this way

   1: <AjaxControlToolkit:PopupControlExtender ID="TextBox1_PopupControlExtender" BehaviorID="pce" runat="server"  

   2:       TargetControlID="tbPrompt" PopupControlID="popupPanel" Position="Bottom">  

As you can see the BehaviorID property is set to “pce”. Now you can write this client side javascript code.

   1: function pageLoad() {   

   2:            //find the PopupControlExtender's client behavior   

   3:            var pce = $find("pce");   

   4:            //add the shown event handler   

   5:            pce.add_shown(pceShownHandler);   

   6:        }   

   7:  

   8:        function pceShownHandler(sender, args) {   

   9:            var pce = $find("pce");   

  10:            //find the popup Panel of the PopupControlExtender   

  11:            var popup = pce._popupElement;   

  12:            var input = popup.getElementsByTagName("input");   

  13:            for (i = 0; i < input.length; i++) {   

  14:                // To check whether the TextBox is the "setFocusToMeOnPopup".   

  15:                // This is just a sample, please modify this condition yourself.   

  16:                if (input[i].id == "FocusTextBox1_setFocusToMeOnPopup") {   

  17:                    input[i].focus();   

  18:                    input[i].select();   

  19:                }   

  20:            }   

  21:        }   

As you can verify from line3, the $find(“pce”) finds the javascript object that contains the client side scripting function of the PopupControlExtender, so you can use the add_shown method to register a client side script to execute when the popup opens. If I use the same technique, when I drop two instance of my usercontrol in the page I obtain this javascript error.

Error: Sys.InvalidOperationException: Two components with the same id ‘pce’ can’t be added to the application.

The reason is that BehaviorID must be unique in the page. The solution is quite simple, first of all I insert this function in the jQuery script.

   1: function pceShownHandler(sender, args) {

   2:     var txtControl = sender._parentElement;

   3:     $(txtControl).parents('.hierarchicmaindiv').find('#txtSearch').focus();

   4: }

This is the function I want to register with the add_shown method, it simply get the textbox control with the _parentElement field of the pce object, then it is time of some magical jQuery selector. Each of my usercontrol instance is rendered inside a div with the class hierarchicmaindiv, now I want to find the textbox wiht “txtSearch” id, but I want only the one related to the specific popup.

To reach this goal we need to find the containing div with the parents jQuery function, then with find() function we look for a textbox with the “txtSearch” id but that is also contained in the div. With this little trick I’m sure that you can drop multiple instance of the control in the page without any problem because when the popup opens, I can find the txtSearch textbox inside the popup even when there are multiple txtSearch textbox in the whole page.

Now I need to wireup this function to the add_shown method of the popupcontrolextender, and this can be obtained with this little snippet on the PreRender server events of the UserControl

   1: hierarchicPce.BehaviorID = Guid.NewGuid.ToString()

   2:  

   3: Dim script As String = _

   4: "Sys.Application.add_load(function() {" & _

   5:  "var pce = $find('" & hierarchicPce.BehaviorID & "');" & _

   6:  "pce.add_shown(pceShownHandler);" & _

   7: "});"

   8:  

   9: Page.ClientScript.RegisterStartupScript(Me.GetType(), hierarchicPce.BehaviorID, script, True)

To avoid duplication of BehaviorID I use a guid, then I create a stupid and little script that uses Sys.Application.add_load() method of Microsoft Ajax library  to register a couple of javascript lines of code :) , the first finds the PopupControlExtender client side object using the guid assigned to BehaviorId and the second one cals the add_shown function to register the function to give focus to correct control.

alk.

Tags:



kick it on DotNetKicks.com

Tags: ,

alkampfer on February 27th, 2010

With VS2010 RC MS had released a vhd to evaluate Lab Management. This is a very good news, and since I already have a Beta2 Lab Management Up and running I want to try the VHD to see what is improved on RC.

Lab Management is and environment, so there is not a way you can simply launch the vhd and play with it, you absolutely need to setup an environment and follow this detailed tutorial. The first problem is, “How I can evaluate lab management without disturbing my main system?”.

The easiest way if you have windows 7 (And you should :) ) is sysprepping a vhd with an image of windows server 2008 R2 (I choosed enterprise), then follow instructions by Scott to boot from vhd and the game is done. You have a dual boot without disturbing the main system, without partitioning etc etc.

Once you boot from vhd the sysprepped image will finish to install the operating system, then you can install hyper-v role and begin the installation of Lab Management :) how cool.

alk.

Tags:



kick it on DotNetKicks.com

Tags: ,

alkampfer on February 26th, 2010

Working with open source software is fun, but sometimes can be difficult. Take as example castle and Nhibernate, since castle references nh with the NHIntegration facility, and at the same time NH references castle for Dynamic Proxy.

A good way to survive this chaos, is working with the trunk, as I usually do, but compiling everything can be quite complex, but we are lucky because we have a project called Horn that does everything for you.

First of all you need to install nsysgit first of all you need to grab the latest source of horn with the comand “git clone git://github.com/dagda1/horn_src.git”. Once you get the source, you need to modify a source file called /src/horn.console/program.cs, in this file there is a function called GetRootFolderPath that ends with a line like

   1: var ret = new DirectoryInfo(rootFolder);

This line needs to be modified with the following line

   1: var ret = new DirectoryInfo(@"d:\osdevelop\horn_src\" + PackageTree.RootPackageTreeName);

clearly the D:\osdevelop\horn_src is my physical path where git extracted horn source code. Now you can go project root and run the HornBuild.bat. If the compilation is successful the horn library was compiled correctly, so you can go to /src/build/net-3.5/debug and you should find a program called horn.exe. Go to this location with a command line and type

   1: horn -install:castle.facilities.nhibernateintegration

with this command horn try to build everything needed for castle facilities nhibernate integration, so horn contacts all various repositories of all the needed libraries, it downloads the latest source and compiles everything. IF everything is gone good, you can simply go to the directory .horn\result and find all the dll’s :) without worrying about order of compilation, source repositories etc etc.

Alk.

Tags:

Tags:



kick it on DotNetKicks.com

Tags: ,

alkampfer on February 25th, 2010

A good option to customize TFS2010 build workflow is creating a Custom Activity, an operation that is quite different from creating a Custom Code Activity. A custom activity does not contain any code at all and it is only composed by sub activities. This kind of customization is really useful to create pieces of workflow that will be inserted in main build workflow. As an example I created a simple custom activity to deploy a database project on a custom Database Server.

The overall operation was already covered in this post, but as you can see that technique involved a MsBuild Activity and you needed to specify values with a really bad “command line parameter” syntax.

Immagine1

Specifying parameter with this technique is awkward and error prone. To solve this situation you can simply create a custom activity. Once you created it, you need to go to “Arguments” tab and insert all the input and output parameters you need.

Immagine2

With this approach, you can use default value for arguments, and you can specify the exact type for arguments, so the workflow can do type checking against the input arguments. I’ve inserted all the input parameters I need: database name, server name, dbProjectname etc etc. Inside the Activity I simply drop a sequence and inside the sequence all the actions needed to deploy the database. The exact technique is described in my old post, the only remarkable difference is logging, because now I can directly drop a WriteBuildMessage activity inside the sequence to log messages. Here is the final activity

Immagine3

Once you have compiled this, you can insert in the build workflow. The great advantage of this approach is that you are now able to specify parameters with great easy.

Immagine4

Compare this with the original approach, where you needed to insert the string

"/p:TargetDatabase=NorthwindTest" +
" /p:""DefaultDataPath=C:Program FilesMicrosoft SQL ServerMSSQL10.SQL2008MSSQLDATA""" +
" /p:""TargetConnectionString=Data Source=10.0.0.99SQL2008,49400%3Buser=sa%3Bpwd=Pa$$w0rd""" +
" /p:DeployToDatabase=true"

Directly inside the CommandLineArgument of MsBuild activity. Now each parameter can be specified alone, and the whole action is much more readable.

Clearly the output result is exactly the same as before, because under the hood it is composed by exactly the same sequence of actions, but now they are all wrapped inside a single Activity, making the workflow more readable.

alk.

Tags:



kick it on DotNetKicks.com

Tags: ,