Question

Has anyone ever used Solrnet inside CLR Stored Procedures? I would really appreciate pointers to some good tutorials.

One problem I'm facing is that I can't find a way to include the SolrNet library as a reference to the VS (2008) Database (SQL Server) Project.

Update:

So it seems that when you have an SQL Server Project, and you want to add a reference to a library, it has to first exist in SQL Server itself, which makes sense. This is done by creating an assembly in SQL Server from the DLL itself with the following SQL:

CREATE ASSEMBLY SolrNet FROM 'C:\CLR_SP\SolrNet.dll' 
WITH   PERMISSION_SET = UNSAFE

(Note that UNSAFE might have some repercussions on the security of the database however it is ok for me for now)

However the SolrNet.dll requires other library dependencies such as Castle.Windsor.dll (which in itself requires System.Core.dll) and Ninject.dll. I found the required version of Castle.Windsor.dll (which is 2.5.1.0) and also System.Core.Dll (which was in the .Net folder of Windows), however I cannot find the required version of Ninject.dll (which should be 2.1.0.76). I have attempted to create assembly version 2.2 but, as expected, it did not do the job.

I searched for it on different repositories but could not find it. Does anyone know where I could find this version of DLL?

Update 2:

So after lots of searching over the net, I still didn't manage to find Ninject.dll v2.1.0.76. My next attempt was to use the next version of SolrNet (which is v0.4.0.2002). This version required Ninject.dll v2.2 which I had already found. So my current status is registering all other libraries in SQL Server which are dependencies of SolrNet.dll. I will leave this open to document my process just in case there will be someone having the same problem.

Update 3:

I have managed to register all required libraries (some of which I got from SolrNet source on GitHub). So now, SolrNet is registered as an assembly in SQL Server, and therefore I can reference it from the .NET SQL Server Project (for creating the CLR Stored Procedure). So I have written a very simple CLR SP which connects to SOLR and retrieves a piece of data. Code below:

[Microsoft.SqlServer.Server.SqlProcedure]
public static void PrintToday()
{
    SqlPipe p;
    p = SqlContext.Pipe;
    p.Send("Helloooo");

    // Open Solr instance
    SolrNet.Startup.Init<ActiveProduct>("http://192.168.2.190:8983/solr");

    // Get instance of ActiveProduct
    ISolrOperations<ActiveProduct> operations = ActiveProduct.GetActiveProductSolrOperations();

    // Prepare QueryOptions. This will be passed as a parameter into the query() method.
    SolrNet.Commands.Parameters.QueryOptions qo = new QueryOptions();

    qo.Start = 0;
    qo.Rows = 20;

    // Query Solr
    SolrQueryResults<ActiveProduct> results = operations.Query(new SolrQueryByField("SearchDescription", "pants"), qo);

    // Read results
    String s = "Docs found: " + results.NumFound;
    p.Send(s);
}

My next problem is that when I deploy and run the CLR SP, an error is popping stating that Solr is already registered in container. The exact output that I see in SQL Server Management Studio is the following:

Helloooo
Msg 6522, Level 16, State 1, Procedure PrintToday, Line 0
A .NET Framework error occurred during execution of user defined routine or aggregate 'PrintToday': 
System.ApplicationException: Key 'SolrNet.Impl.SolrConnection.CLRStoredProcedures2.ActiveProduct.SolrNet.Impl.SolrConnection' already registered in container
System.ApplicationException: 
   at SolrNet.Utils.Container.Register(String key, Type serviceType, Converter`2 factory)
   at SolrNet.Utils.Container.Register[T](String key, Converter`2 factory)
   at SolrNet.Startup.Init[T](ISolrConnection connection)
   at SolrNet.Startup.Init[T](String serverURL)
   at StoredProcedures.PrintToday()

PrintToday is the name of the CLR StoredProcedure

CLRStoredProcedures2 is the name of the .NET SQL Server project and default namespace in VS 2008

ActiveProduct is the name of the document in Solr, and the cs class with Solr annotations

As can be seen from the output, the first Pipe.send("Hellooo") is doing its job therefore the SP works fine until there.

When I searched for the above error, I found out that it will show when one tries to register Solr instance twice in the same application. Now I don't see where I am registering the instance twice. Am I missing something here?

Note that the above cs function worked fine when executed in a cs console application developed on my machine. Another detail which might be important is that the SOLR Server is being hosted on my machine which is on the same network of my SQL Server 2005.

Update 4:

For starters, the error I mentioned above (in update 3) does not fire when the SP is executed the 1st time just after deployment (let's assume that the 1st time works for now since I have another error which I'm currently working on fixing), the error fires when the SP is executed again afterwards. So it seems that whatever SolrNet.Startup.Init<ActiveProduct>("http://192.168.2.190:8983/solr"); is doing (creating some sort of session that has to do with a container I think) when called from the SP it is not releasing the "session" therefore the 2nd time (and each time afterwards) the SP is executed, the error is fired. Is there a way to sort of stop the session or releasing from the container. What I can do as a workaround is to try - catch the SolrNet.Startup.Init part, however this is not clean.

Thanks.

Was it helpful?

Solution

I'll try to summarize the steps / requirements with explanations whenever possible:

  • For some reason SQL Server seems to trigger the "hidden" dependencies of the merged SolrNet. Usually you can just use the merged SolrNet (which includes all integration modules) and if you ignore the integration classes the dependencies won't trigger. But in this case the unmerged SolrNet is necessary.
  • SolrNet does HTTP requests to the Solr server, so the DLL must be registered with UNSAFE permissions in SQL-CLR.
  • SolrNet Initialization (Startup.Init) must happen only once per application, but you don't have a 'root' context in SQL-CLR to place this initialization. A workaround is to use a singleton or a Lazy type. SQL-CLR doesn't run .NET 4 yet, but you can backport the Lazy type or use FSharp.Core.dll's implementation (I blogged about this some time ago)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top