Repository pattern with LINQ to SharePoint DSL Extension (part 3)
In the part 1 of this tutorial and the part 2, I explained how the Repository pattern of the LINQ to SharePoint DSL Extension for Visual Studio 2010 is working.
In this new post, I show how to extend the repositories to add your own methods to the business layer. I show also how to use advanced settings as the factory load from a web.config key.
How to extend the repositories
You can implement your own business rules in a repository because all the classes and interfaces generated by the LINQ to SharePoint DSL Extension use the .Net “partial” keyword.
Then, to extend the repository pattern, you only need to write some complementary code to the existing repositories classes. You must implement this code in separate files and write two things:
- Declare new methods prototypes in the IEntityRepository interface
- Implement these new methods in the EntitiesLinqRepository class
For example, if you have an entity called Model, and a repository of type IModelRepository, you could add your own methods in this repository thanks to the following code.
First, extend the repository interface:
/// <summary>
/// This sample shows how to extend the Models repository to insert custom business methods inside.
/// This code has been written manually and will not be erase during repositories generation.
/// To extend a repository, first declare new methods inside the interface.
/// </summary>
public partial interface IModelsRepository
{
/// <summary>
/// Gets a list of models contained in the specified category.
/// </summary>
/// <param name="category">The category.</param>
/// <returns></returns>
IEnumerable<Model> GetModelsByCategory(System.Nullable<int> category, int limit);
….
}
Secondly, extend the repository LINQ implementation class:
/// <summary>
/// This sample shows how to extend the Models repository to insert custom business methods inside.
/// This code has been written manually and will not be erase during repositories generation.
/// This class adds new methods inside the repository LINQ to SharePoint concrete implementation.
/// </summary>
public partial class ModelsLinqRepository
{
/// <summary>
/// Gets a list of models contained in the specified category.
/// </summary>
/// <param name="category">The category.</param>
/// <param name="limit">The limit.</param>
/// <returns></returns>
public IEnumerable<Model> GetModelsByCategory(System.Nullable<int> category, int limit)
{
/// Call a repository helper method thanks to the Factory property in the repositories classes
IQueryable<Product> products = this.Factory.Products.GetByCategoryId(category).Where(c => c.SellEndDate == null || c.SellEndDate > DateTime.Now);
List<Model> models = new List<Model>();
IEnumerable<IGrouping<Model, Product>> productsByModel = products.ToList().GroupBy(c => c.Model);
if (limit >= 0)
productsByModel = productsByModel.Take(limit);
foreach (IGrouping<Model, Product> p in productsByModel)
models.Add(p.Key);
return models;
}
…
}
Now you can call this new method in your code:
using (IAdventureWorksFactory factory = AdventureWorksFactory.GetNewInstance(SPContext.Current.Web.Url))
{
//Call the new custom repository method
IEnumerable<Model> models = factory.Models.GetModelsByCategory(int.Parse(catId), 10);
// Databinds the results data in a data list ASP.Net web control
if (models == null || models.Count() == 0)
this.DataListProducts.Visible = false;
else
{
this.DataListProducts.DataSource = models;
this.DataListProducts.DataBind();
}
}
With this technical, you can easily extend the repository layer with your own business needs. This method helps the developers to use a federated point to code the business methods of the application and reuse it everywhere in the application.
Advanced settings
You can notice that, by default, the repository layer factory instances the concrete factory class with the default LINQ to SharePoint implementation. If you want to use a different implementation (for example to test your code is a different data context), you can define the concrete implementation type in web.config (or app.config) key. This method could help you to reduce the level of dependency between your code and the method used to connect to the data.
To use this feature, you must add a new key in your web.config appsettings section, like it:
<add key="FactoryClass" value="AdventureWorksLT.Repository.Business.AdventureWorksLinqFactory, AdventureWorksLT.Repository, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce71d4a92991e51e" />
You can notice that the defined factory class must implement the "IXXFactory" type generated for your model.
To generate a repository layer with this new factory type, you must edit the TT file and set the parameters about it (USE_WEB_CONFIG_FACTORY_TYPE_LOADER, etc.), save it, and run the custom tool again to regenerate the code.
If you do that, the GetNewInstance method of the factory class will use reflection to invoke dynamically the factory instance.
Note: using reflection to construct the factory is slower than the default method. Only use it if you need this feature, and keep the default method if not.