Tuesday, October 12, 2010

Run multiple instances of an app on Mac OS X

Click Applications on Dock, select Automator. Choose Application. On searchbox, type: shell. Choose Run Shell Script, double click it. Then on text area, replace it with this text:

if [ -n "$*" ]; then
    open -n "$*"
else
    osascript -e 'tell app "Finder" to display dialog "PLZ DRAG AN APP 2 MULTIPLE INSTANCE" with title "MULTIPLE INSTANCE LAUNCHER" buttons { "OH HAI" } '
fi

On Pass input, change it to as arguments. Press command+S, on Save as type: Multiple Instance, on Where, choose Applications, click Save. Quit Automator.

Click Applications, drag Multiple Instance to Dock, preferably near Applications folder.

Click Applications, drag an app(example: Calculator) to Multiple Instance, repeat to launch multiple instance of that app.

Watch it on YouTube

Tuesday, October 5, 2010

Linq to SQL is not a perfect match for reporting needs

Is clean (or performant) SQL achievable in Linq to Sql?

I wanted Linq to Sql produce this code:

SELECT C.CustomerID, COUNT(O.CustomerID) AS N
FROM Customers C
LEFT JOIN Orders O ON O.CustomerID = C.CustomerID
GROUP BY C.CustomerID

Here's my first attempt:

var q = 
from c in db.Customers
join o in db.Orders on c.CustomerID equals o.CustomerID into sr
from x in sr.DefaultIfEmpty()
group x by c.CustomerID into y
select new { y.Key, N = y.Count(t => t.CustomerID != null) };


First, my beef with Linq is it cannot allow the natural way to write a query. For comparison expressions, it is best to put on the left side the value/expression that is varying much, the less varying ones(e.g. constants) should be on the right side. To convey the point:

int customerId = 7;
bool found = false;
for(int i = 0; i < orders.Length; ++i)
{
    if(orders[i].CustomerId == customerId)
    {
        found = true;
        break;
    }
}

Linq doesn't allow this kind of statement:
var q = from c in db.Customers
        join o in db.Orders on o.CustomerID equals c.CustomerID into sr


Writing query on this form: from c in db.Customers join o in db.Orders on c.CustomerID equals o.CustomerID into sr is akin to doing this code:

int customerId = 7;
bool found = false;
for(int i = 0; i < orders.Length; ++i)
{
    if(customerId == orders[i].CustomerId)
    {
        found = true;
        break;
    }
}

Well that code just doesn't feel natural, isn't it?


Back to the gist of this topic, is performant code achievable in Linq to SQL?

The Linq to SQL code above produces:

SELECT [t2].[CustomerID] AS [Key], (
    SELECT COUNT(*)
    FROM [Customers] AS [t3]
    LEFT OUTER JOIN [Orders] AS [t4] ON [t3].[CustomerID] = [t4].[CustomerID]
    WHERE ([t4].[CustomerID] IS NOT NULL) AND ((([t2].[CustomerID] IS NULL) AND ([t3].[CustomerID] IS NULL)) OR (([t2].[CustomerID] IS NOT NULL) AND ([t3].[CustomerID] IS NOT NULL) AND ([t2].[CustomerID] = [t3].[CustomerID])))
    ) AS [N]
FROM (
    SELECT [t0].[CustomerID]
    FROM [Customers] AS [t0]
    LEFT OUTER JOIN [Orders] AS [t1] ON [t0].[CustomerID] = [t1].[CustomerID]
    GROUP BY [t0].[CustomerID]
    ) AS [t2]

Well, that is far cry from the simple thing we want to achieve; that is, Linq's Count(expression here) should not produce COUNT(*), it should produce COUNT(O.CustomerId), but since we cannot feed non-lambda operation on Linq's Count's parameter, we must do: select new { y.Key, N = y.Count(t => t.CustomerID != null) };. And that code produces inefficient query, look at the Sql output above.

Here's my second attempt...

var q = 
from c in db.Customers
join o in db.Orders on c.CustomerID equals o.CustomerID into sr
from x in sr.DefaultIfEmpty()
group x by c.CustomerID into y                                        
select new { y.Key, N = y.Sum(t => t.CustomerID != null ? 1 : 0 )};

...that code produces:

SELECT SUM(
    (CASE
        WHEN [t1].[CustomerID] IS NOT NULL THEN @p0
        ELSE @p1
     END)) AS [N], [t0].[CustomerID] AS [Key]
FROM [Customers] AS [t0]
LEFT OUTER JOIN [Orders] AS [t1] ON [t0].[CustomerID] = [t1].[CustomerID]
GROUP BY [t0].[CustomerID]

Though cleaner and performance-wise is passable, it still leave much to be desired, it doesn't inline constants; parameters might be the way of Linq to Sql for passing values or expressions to query(be it a variable or constant), however it still doesn't have a natural feel into it. As far as I know, there's no way to make Linq-to-Sql produce this SQL code: COUNT(O.CustomerId)


Linq to Sql is good as an ORM, storage persistence, fetching data, CRUD operations; but for reporting needs, I wouldn't bet my farm on it though. I would continue using plain old combo of SP,functions,views and ADO.NET for reporting needs.

Saturday, October 2, 2010

NullReferenceException on GetEntryAssembly

I'm following an MVC lesson from Steven Sanderson book. There's an error which eludes me, but solved by just changing the erring function to other equivalent function.


Server Error in '/SportsStore' Application.


Object reference not set to an instance of an object.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

Source Error:

Line 39:             
Line 40: 
Line 41:             var controllerTypes = from t in Assembly.GetEntryAssembly().GetTypes()
Line 42:                                   where typeof(IController).IsAssignableFrom(t)
Line 43:                                   select t;






That problem can be solved by changing GetEntryAssembly to GetExecutingAssembly

Castle Windsor warning on AddComponentLifeStyle is obsolete

Wrong warning...


Warning 1 'Castle.Windsor.WindsorContainer.AddComponentLifeStyle(string, System.Type, Castle.Core.LifestyleType)' is obsolete: 'Use Register(Component.For(classType).Named(key)).Lifestyle.Is(lifestyle)) instead.' C:\_CODE\SportsStore\SportsStore\Controllers\WindsorControllerFactory.cs 37 17 SportsStore


...for this kind of code:


container.AddComponentLifeStyle(t.FullName, t, LifestyleType.Transient);

If you try to type LifeStyle after of Named(t.FullName)) ...

container.Register(Component.For(t).Named(t.FullName)).LifeStyle.Is(LifestyleType.Transient));

...the VS Intellisense will not kick in. 

Lifestyle doesn't belong to container.Register, Lifestyle belongs to  Component.For.Named.  This is the correct code, just remove the extra close parenthesis on Named:

container.Register(Component.For(t).Named(t.FullName).LifeStyle.Is(LifestyleType.Transient));

Login failed for user IIS APPPOOL\DefaultAppPool troubleshooting

This error...


Cannot open database "SportsStore" requested by the login. The login failed.
Login failed for user 'IIS APPPOOL\DefaultAppPool'.
A severe error occurred on the current command.  The results, if any, should be discarded.



...has this solution:


Open Microsoft SQL Server Management Studio

Go to Logins node under Security.

Add a new Login, name it: IIS APPPOOL\DefaultAppPool



Then select the User Mapping on left pane, then check the Map column of your database (e.g. SportsStore).  Then check the db_owner on Database role membership of your user IIS APPPOOL\DefaultAppPool on your database SportsStore