Blog on development in general, and specifically on .NET
If you expose in your entity a collection of a type other than ICollection<T> (or one inheriting from it, such as IList<T>) then it will be ignored. This is a bit absurd, because you might want to expose a collection as read only, where you would probably use IEnumerable<T>. For the record, NHibernate allows that.
A possible solution is to have a non-public field of type ICollection<T> and to expose it as an IEnumerable<T> property. The problem is that you won’t be able to use the property in LINQ queries, because it is not mapped. And conventions won’t help either, because you cannot configure collections there.
Here I will list some of NHibernate’s hidden or not so well known gems.
This is part of a series of posts about NHibernate Pitfalls. See the entire collection here.
Normally, in an HQL query, you can omit the select clause, that is, the two queries are identical:
However, if you add joins, then it’s a whole different matter:
Worse, queries q3 and q4 will not filter distinct root entities, meaning, you will get the cartesian product of Product x OrderDetail.
So, you will need to select the root entity (select p), plus add a distinct entity result transformer (Transformers.DistinctRootEntity) to get what you want:
This doesn’t happen with LINQ, it always performs a distinct root entity selection, but it also happens with Criteria and QueryOver.
Did you know that you can leverage NHibernate’s built-in proxy generator to inject custom behavior in your classes? It is called NHibernate.Proxy.DynamicProxy.ProxyFactory and there’s an interface, NHibernate.Proxy.DynamicProxy.IInterceptor, that you can use to extend it, by intercepting method and property calls.
First, you inject an NHibernate interceptor, inheriting from EmptyInterceptor, in the configuration instance, before building the session factory:
The code in the Instantiate method will add the INotifyPropertyChanged interface to the generated proxy instance, a common interface that is used for detecting property changes.
But the real fun is in the NHibernate.Proxy.DynamicProxy.IInterceptor implementation:
This will detect calls to properties (starting with set_) and, after they complete, will raise the PropertyChanged event. This will save you lots of lines in your code!
You just need to register the NHibernate interceptor, and your done:
And from now one, all your entities automagically implement INotifyPropertyChanged:
If you want to store anything in a property of an entity, you can declare it as Object or dynamic; as long as you set it to a value of a serializable type, as supported by BinaryFormatter, you’re good! You can even change the value afterwards to a different type, and it will be saved.
You map it like this, in mapping by code:
NHibernate will return the same object type and all of its contents anytime you retrieve it.
Try that in other persistence frameworks!
Speech synthesis and recognition were both introduced in .NET 3.0. They both live in System.Speech.dll. In the past, I already talked about speech synthesis in the context of ASP.NET Web Form applications, this time, I’m going to talk about speech recognition.
.NET has in fact two APIs for that:
System.Speech, which comes with the core framework;
Microsoft.Speech, offering a somewhat similar API, but requiring a separate download: Microsoft Speech Platform Software Development Kit.
I am going to demonstrate a technique that makes use of HTML5 features, namely, Data URIs and the getUserMedia API and also ASP.NET Client Callbacks, which, if you have been following my blog, should know that I am a big fan of.
First, because we have two APIs that we can use, let’s start by creating an abstract base provider class:
It basically features one method, RecognizeFromWav, which takes a physical path and returns a SpeechRecognitionResult (code coming next). For completeness, it also implements the Dispose Pattern, because some provider may require it.
In a moment we will be creating implementations for the built-in .NET provider as well as Microsoft Speech Platform.
The SpeechRecognition property refers to our Web Forms control, inheriting from HtmlGenericControl, which is the one that knows how to instantiate one provider or the other:
The control exposes some custom properties:
Culture: an optional culture name, such as “pt-PT” or “en-US”; if not specified, it defaults to the current culture in the server machine;
Mode: one of the two providers: Desktop (for System.Speech) or Server (for Microsoft.Speech, of Microsoft Speech Platform);
SampleRate: a sample rate, by default, it is 44100;
Grammars: an optional collection of additional grammar files, with extension .grxml (Speech Recognition Grammar Specification), to add to the engine;
Choices: an optional collection of choices to recognize, if we want to restrict the scope, such as “yes”/”no”, “red”/”green”, etc.
The mode enumeration looks like this:
The SpeechRecognition control also has an event, SpeechRecognized, which allows overriding the detected phrases. Its argument is this simple class that follows the regular .NET event pattern:
Which in turn holds a SpeechRecognitionResult:
This class receives the phrase that the speech recognition engine understood plus an array of additional alternatives, in descending order.
You need to add an assembly-level attribute, WebResourceAttribute, possibly in AssemblyInfo.cs, of course, replacing MyNamespace for your assembly’s default namespace:
This attribute registers a script file with some content-type so that it can be included in a page by the RegisterClientScriptResource method.
And here is it:
OK, let’s move on the the provider implementations; first, Desktop:
What this provider does is simply receive the location of a .WAV file and feed it to SpeechRecognitionEngine, together with some parameters of SpeechRecognition (Culture, AudioRate, Grammars and Choices)
Finally, the code for the Server (Microsoft Speech Platform Software Development Kit) version:
As you can see, it is very similar to the Desktop one. Keep in mind, however, that for this provider to work you will have to download the Microsoft Speech Platform SDK, the Microsoft Speech Platform Runtime and at least one language from the Language Pack.
Here is a sample markup declaration:
If you want to add specific choices, add the Choices attribute to the control declaration and separate the values by commas:
Or add a grammar file:
By the way, grammars are not so difficult to create, you can find a good documentation in MSDN: http://msdn.microsoft.com/en-us/library/ee800145.aspx.
And that’s it. You start recognition by calling startRecording(), get results in onSpeechRecognized() (or any other function set in the OnClientSpeechRecognized property) and stop recording with stopRecording(). The values passed to onSpeechRecognized() are those that may have been filtered by the server-side SpeechRecognized event handler.
A final word of advisory: because generated sound files may become very large, do keep the recordings as short as possible.
Of course, this offers several different possibilities, I am looking forward to hearing them from you!
Back to MVC land! This time, I wanted to be able to load controllers and views from an assembly other than my application. I know about the extensibility mechanisms that ASP.NET and MVC give provides, such as Virtual Path Providers and Controller Factories, so I thought I could use them.
First things first: we need a controller factory that can load a controller from another assembly:
Next, we need to be able to load view files from an assembly, and a virtual path provider is just what we need for that:
These three classes inherit from VirtualPathProvider, VirtualFile and CacheDependency and just override some of its methods. AssemblyVirtualPathProvider first checks with other virtual path providers if a file exists, and only if it doesn’t does it create the AssemblyVirtualFile. This looks up the virtual file name in the assembly’s resources, using a convention that translates slashes (/) per dots (.) and returns it. As for the AssemblyCacheDependency, we need it because otherwise ASP.NET MVC will think that the file exists in a directory and will try to monitor it, and because the directory and file do not exist, it will throw an exception at runtime.
We also need a bootstrapping class for setting up everything:
Finally, for this to work, we need three things:
- The controller must be public, have a parameterless constructor, and its name must end with Controller (the default convention);
- View files must be compiled as embedded resources in the assembly:
- And finally, we need to set this up in Global.asax.cs or RouteConfig.cs:
By the way, the AssemblyVirtualPath provider, AssemblyVirtualFile and AssemblyCacheDependency are pretty generic, so you can use them in other scenarios.
That’s all, folks!
A long, long time ago, I wrote a NHibernateDataSource control. Back then, it was based in the first LINQ provider for NHibernate, and a long has happened since. Now, I decided to give it another go!
Historically, in ASP.NET, a data control should inherit from DataSourceControl, like ObjectDataSource, LinqDataSource, EntityDataSource, SqlDataSource, etc, and should expose collections for parameters for each of the supported operations (select, update, delete and insert). Since ASP.NET 4, however, a new base class came along: QueryableDataSource. This class is an implementation of IQueryableDataSource, which allows using QueryExtender, also introduced in version 4, to filter and sort the results of a data source that uses LINQ.
I wanted my control to be able to use QueryExtender, but I also wanted to be able to give it an HQL query. It should also be capable of inserting, updating and deleting entities.
So, here’s what I came up with, first, the NHibernateDataSource class:
You can see that it exposes some events:
- Configure: gives developers a chance to build (or return an existing) Configuration instance, that will be used for building the session factory;
- BuildSessionFactory: allows setting parameters on the default session factory or returning an existing one;
- CreateInstance: raised before NHibernate creates a default instance, to allow developers to return one;
- EntityInserting: raised before an entity is inserted, allowing developers to cancel the operations or to set entity parameter;
- EntityUpdating: raised before an entity is updated, allowing developers to cancel the operations or to set entity parameter;
- EntityDeleting: raised before an entity is deleting, allowing its cancellation;
- EntitiesSelecting: raised before a select operation is performed;
- EntityInserted: raised after an entity was inserted;
- EntityUpdated: raised after an entity was updated;
- EntityDeleted: raised after an entity was deleted;
- EntitiesSelected: raised after a select operation was performed;
- OperationCompleted: raised after an operation completes (select, insert, update or delete).
If no handler for CreateInstance is supplied, NHibernateDataSource will try to create an entity using Activator.CreateInstance.
EntitySelecting is raised regardless of the Mode (Hql or Linq), but it will have different values in its argument: a query string plus parameters in the case of Hql and an IQueryable instance for Linq.
EntityInserting, EntityUpdating and EntityDeleting allow the modification of properties of the entity in the parameter, but not the replacing of the entity itself.
OperationCompleted is always called, except in the event of an exception.
It also exposes a couple of properties:
- Mode: one of the two operation modes, Hql or Linq. If Hql is used, then the Hql property must be set; otherwise, it’s EntityName that is required;
- Hql: an NHibernate HQL query string;
- EntityName: the name of an entity that the control will work with; only required for Mode Linq or for inserts, updates or deletes;
- RefreshBeforeUpdate: whether NHibernate should refresh the properties of an entity before updating or deleting it;
- MaximumRecords: the optional maximum number of records to retrieve, if paging is not used (PageSize and PageIndex);
- PageIndex: the page index to retrieve;
- PageSize: the page size to retrieve;
- SessionFactory: a session factory that will be used instead of a default created one;
- SelectParameters: a collection of parameters to be applied to the Hql string;
- InsertParameters: a collection of parameters for the insert operation;
- UpdateParameters: a collection of parameters for the update operation;
- DeleteParameters: a collection of parameters for the delete operation.
And, of course, exposes the basic operations: select is the default, but Insert, Update and Delete methods are available.
NHibernateDataSource will check if the SessionFactory property is set, otherwise, it will build its own Configuration instance and raise the Configure and BuildSessionFactory events. The generated session factory is then stored in the InternalSessionFactory static property for caching.
Then, the NHibernateDataSourceView, which is the responsible for the actual querying, inheriting from QueryableDataSourceView:
And the NHibernateDataSourceMode:
Finally, all of the event arguments:
Now, let’s see concrete examples of its usage. First, using Mode Hql:
You can see that the Hql property has a parameter, price, which is bound to a parameter in SelectParameters with the same name. Each parameter is an instance of the Parameter class, here I am using a parameter with a static value (Parameter) and another that takes a value from the query string (QueryStringParameter), but others exist. To help with NHibernate insert and update operations, I created a new Parameter class, EntityParameter, that knows how to retrieve a en entity or a proxy to an entity:
As for Mode Linq, an example using a QueryExtender is in order:
The LINQ query produced by the NHibernateDataSource is intercepted by the QueryExtender and a where (SearchExpression) and a order by (OrderByExpression) clauses are added to it. Other expressions can be used, inheriting from DataSourceExpression, and some take parameters of type Parameter. Do notice that filtering and sorting is performed server-side, not client-side.
Of course, this can certainly be improved, let me hear your thoughts and questions.
And that’s it. Enjoy!
Like I said in my previous post, it’s not enough to add a DbFunctionAttribute attribute to a method to have it call a database function. If the function is not a built-in one, it will not be registered in the Entity Framework provider manifest for SQL Server, so it will require registration in the model. You might think, just by looking at the methods in SqlFunctions that all that it took was to add this attribute, but you would be wrong.
It is possible to register custom functions that exist in the database so that they can be called by Entity Framework Code First LINQ queries.
If we want this method to be callable by a LINQ query, we need to add the DbFunctionAttribute to it, specifying the name of the database function we wish to call, because the .NET method and the database function names can be different:
And for calling it:
However, for certain database functions, it requires a bit more work to get done. Let us consider now the FORMAT function and a .NET implementation:
Besides adding the DbFunctionAttribute attribute:
it also requires that we register it explicitly in our model, for that, we override the OnModelCreating method and add a custom convention:
The convention being:
Now we have the FORMAT function available to LINQ:
Now, I hear you ask: why for SOUNDEX we just need to add a simple attribute and for FORMAT we need so much more? Well, it just happens that SOUNDEX is defined in the Entity Framework SQL Server provider manifest - see it here. All of the functions in SqlFunctions are present in the manifest, but the opposite is not true - not all functions in the manifest are in SqlFunctions, but that's the way it is! Thanks to @divega for the explanation.
Some things worth mentioning:
You cannot specify two functions with the same name and different parameters.
There is an open request to add the FORMAT function to the list of functions supported out of the box by Entity Framework Code First: https://entityframework.codeplex.com/workitem/2586 through the SqlFunctions class, but in the meantime, this might be useful!