Contents tagged with .NET
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!
SharePoint offers a couple of ways by which we can obtain the current user for use in a XSLT web part like DataFormWebPart or XsltListViewWebPart. All involve first setting parameters through the ParameterBindings property:
Here we see different kinds of parameters:
- CAMLVariable: built in variables UserID and Today;
- WPVariable: returns one of the predefined values for _WPID_ (web part client id), _WPQ_ (web part unique id in page), _WPR_ (web part resources folder full URL), _WPSRR_ (web part resources folder relative URL), _LogonUser_ (server variable LOGON_USER), _WebLocaleId_ (current site locale, as in CultureInfo.LCID);
- ServerVariable: returns one of the HTTP or IIS server- defined variables.
This will return something like this:
UserID: Ricardo Peres
The ddwrt:UserLookup extension function returns a value depending on the second parameter; valid values are Id, Email and Login, and you can easily guess what they are for.
You can find a reference for LOGON_USER, AUTH_USER, REMOTE_USER and UNMAPPED_REMOTE_USER here. In my development server, I get the same value for all variables.
By the way, I posted a more advanced solution, which allows access to any profile properties. You can read it here.
This page will list all of my book reviews, in no particular order.
Right now, I am reviewing Microsoft Azure Development Cookbook Second Edition, just give me some more days, because it’s a long one.
Microsoft Azure Development Cookbook Second Edition
(Review not yet available)
Windows Presentation Foundation 4.5 Cookbook
NHibernate 2 Beginner's Guide
NHibernate 3.0 Cookbook
Visual Studio 2012 and .NET 4.5 Expert Development Cookbook
NHibernate in Action Book
Instant StyleCop Code Analysis How-to Review
Programming Entity Framework
Pro WF: Windows Workflow in .NET 3.5
I have already shown how you can display all attributes and their values from a XSLT content, but in case you want to look at the whole structure plus their attributes, you can use this instead:
Since version 4, ASP.NET offers an extensible mechanism for encoding the output. This is the content that will be returned to the browser. I already refered it in Providers.
The actual implementation to use can be configured by code or XML configuration (the Web.config file).
The default implementation is always available in the read only property HttpEncoder.Default.
If you prefer to change the Web.config file, you need to set the encoderType attribute of the httpRuntime section:
It is a nice addition, especially together with the validation provider model introduced with ASP.NET 4, which will be the topic of my next post on ASP.NET Web Forms extensibility.
In case you ever want to have a look at the generated SQL before it is actually executed, you can use this extension method:
Parameters such as 100 will be located in the nhLinqExpression.ParameterValuesByName collection.
Another book for which I was a technical reviewer in the Succinctly series just got released: Windows Azure Websites Succinctly. The author is Kyle Burns (@kyleburnsdev), who keeps a blog on development at http://geekswithblogs.net/kyleburns.
So, go get it while it’s hot!
A common request is to be able to retrieve user information from XSLT (XsltListViewWebPart, DataFormWebPart, etc). It is possible to obtain some information through server variables (LOGON_USER), CAML variables (UserID) or ddwrt:UserLookup extension function. It works, to some extent, but sometimes it is not enough.
It is well known that one can have server controls in XSLT stylesheets. As it happens, the ProfilePropertyValue control retrieves any value from the user profile. It just needs to have a ProfilePropertyLoader declared before it, which can be placed in the master page. For example:
Just remember to register the Microsoft.SharePoint.Portal.WebControls assembly with the SPSWC tag prefix, either in the Web.config or in the page itself.
But, what about XSLT? Well, if the SPSWC tag prefix is registered in Web.config, we can do this:
With this technique, you can retrieve any of the profile properties. Ah, don’t forget to add:
To the <xsl:stylesheet> declaration.