[Pet Shop Reloaded] A comparative study between CodeFluent Entities and Entity Framework
Some of you may know the story about the Pet Shop application, a .NET/C# revisited version of the original Java Pet Store application made by Sun Microsystems. These two sample applications were used as a mean to show an implementation of the best practices and features of both technologies. Today, these applications begin to get dusty as they were released on November 2001 and May 2001 respectively.
So the SoftFluent team decided to build a reloaded version of the Pet Shop using CodeFluent Entities. To maintain the spirit of the original concept we also decided to develop a parallel version using Entity Framework.
Indeed, a recurrent question about CodeFluent Entities is how it relates to Entity Framework. SoftFluent has published a white paper giving a large set of details on how these two products differ so one can understand how CodeFluent Entities is much more than an ORM.
We are going to write a series of blog posts showing how some concepts and features can (or cannot) be implemented using CodeFluent Entities and Entity Framework. We may not cover all the concepts or features of the two products (as there are many), but we will treat the main features needed to successfully implement a web application.
We will lead this study case as objective as possible and we will love to discuss any question, remark or feedback people may give us, so don’t hesitate to comment every post.
You can find all the blog posts related to the Pet Shop Reloaded by SoftFluent under the tag “Pet Shop Reloaded“. Stay tuned. ![]()
Cheers,
The SoftFluent team.
Using flags enumeration with ASP.NET MVC and CodeFluent Entities
Enumeration support
CodeFluent Entities provides full support of “enumeration” types and multi value enumerations (flag enumeration).
To declare a multi value enumeration, go to the enumeration type properties and set the, go to the enumeration type properties and set the Multi Value property to True.
And since the build version (646) you can set an enumeration value as the combination of other values (by their name).
Using enumeration values with ASP.NET MVC
Let’s use these concepts on an ASP.NET MVC application, I will use the model above as an example. I also have a MediaController with an Index action to list all Medias and an Edit action (Get and Post).
The default template for an enumeration value is a textbox, so if I write something like this:
@Html.EditorFor(m => m.MediaType)
I will get a textbox for my enumeration value.
This will work but the user will have to write a correct enumeration value, and unless each user knows all the possible enumeration values, this is not an acceptable solution.
It would be better to display a dropdown list instead. Let’s create a template named Choice.cshtml on the Views\Shared\EditorTemplates folder.
@model Enum
@{
var items = from object value in Enum.GetValues(Model.GetType())
select new { Value = value, Text = value.ToString() };
SelectList list = new SelectList(items, "Value", "Text", Model);
}
@Html.DropDownList("", list)
And now if we choose this as the template for our enumeration:
@Html.EditorFor(m => m.MediaType, "Choice")
This works fine and we can use the Choice.cshtml template for any enumeration type.
Using multi enumeration values with ASP.NET MVC
Let’s now do the same work for a multi value enumeration (flag enumeration). First we create a template named MultiChoice.cshtml on the Views\Shared\EditorTemplates folder.
@model Enum
@{
var items = from object value in Enum.GetValues(Model.GetType())
select new { Value = value, Text = value.ToString() };
IEnumerable selected = CodeFluent.Runtime.Utilities.ConvertUtilities.SplitEnumValues(Model);
MultiSelectList list = new MultiSelectList(items, "Value", "Text", selected);
}
@Html.DropDownList("", list, new { multiple = "multiple" })
We use here a method on the CodeFluent.Runtime.Utilities namespace to split a flag value into a list of enumeration values.
Let’s try it for our multi value enumeration.
@Html.EditorFor(m => m.ReleaseFormat, "MultiChoice")
This seems to work but it doesn’t, when I try to save my form, not all values are saved (from the flag multi value enumeration). This is because MVC does not bind correctly the multi value enumeration to my model.
We need to add a custom model binder (System.Web.Mvc.IModelBinder) and a value provider (System.Web.Mvc.IValueProvider). I will use some utilities classes that are used for the ASP.NET Web Site V2 producer, they can be found under the Templates folder in the CodeFluent Entities installation location (Program Files (x86)\SoftFluent\CodeFluent\Modeler\Templates\UI\AspNetMvc\Code\Utilities.cs.tpl). I will copy the content of the file in my ASP.NET MVC project filling the correct namespace. Don’t forget to add a reference to the CodeFluent.Runtime.Web assembly.
Finally, we register the EntityBinder and the EntityValueProviderFactory classes that we have just added. On the Application Start:
ValueProviderFactories.Factories.Add(new EntityValueProviderFactory()); ModelBinderProviders.BinderProviders.Add(new EntityBinder());
This time everything works great.
This post was inspired by the CodeFluent Entities templates when wondering what the ASP.NET Web Site V2 producer generates
.
Regards,
Pablo Fernandez Duran
Defining type mappers when importing a database using the Importer Wizard
You can use the Importer Wizard to import an existing data base as a CodeFluent Entities model. You can access the Importer from the Modeler or the solution explorer on your CodeFluent Entities project (right click).
The importer makes a mapping between the data source types and the CodeFluent Entities types. But, you may want to define your own mapping configuration for a given type.
To do that, go to the “advanced properties” of the Importer Wizard and select “Type Mappers” under the “Input Mapping” group and add your type mapper.
Let’s say I am importing a SQL Server 2012 database and I have a field of type “time” (more information about SQL Server 2012 type mapping here), well I would like to have a CLR type “TimeSpan” mapped to it. When I take a look at the imported model I can see that the mapped type is “time”, but when I generate the Business Object Model (BOM) layer I have a property of type “System.DateTime (nullable)”. This is because the SQL Server type “time” did not exist before the SQL Server 2008 version.
So we can define a “type mapper” for the SQL Server type “time”.
We could also have chosen “System.TimeSpan”, “timespan” or “duration” as the “Type Name”.
And now we have a CLR type “System.TimeSpan (nullable)” in our BOM for a SQL Server 2012 type “time”.
Remember that you can save your Importer Wizard configuration.
You can find more resources about the Importer Wizard here.
Regards,
Pablo Fernandez Duran
Creating a custom sub producer to only generate resources
Generating a CodeFluent Entities model looks at all the producers, and produce each one of them, assuming they have been enabled. The BOM producer is the most important producer and generates classes from your entities. If we break down that producer, we realize that it produces different things, such as templates, resources, membership providers, membership roles, constants…
What if you wanted to only produce resources, and nothing else?
One reason would be that your project has a lot of entities, your model is pretty much finished, but you still need to add resources. Moreover, your project is hosted on TFS online, and you do not want to check out, and check in, all the new generated files, especially if they have not changed!
By default, TFS checks out all the modified files (by a human or a code generator). Then, you need to check them back in. Hosted online, this means that the check in process would contain almost all the files of your BOM and it could be time consuming.
In this post we will create a custom sub producer that will only generate resources, and nothing else.
1. Creating the project
First, you need to create a new class library project, add some of the CodeFluent Entities references as well as 2 classes (BuildOnlyResources.cs and Constants.cs):
2. Writing classes
The BuildOnlyResources class extends the ICodeDomSubProducer interface to plug itself into the OnCodeDomProduction event. The first thing to do is to cancel the production of everything besides Resources. To do this, we check the eventType retrieved from the parameter of the OnCodeDomProduction method, and set the cancel property to true.
At this stage, the sub producer will stop generating all files, except the resources. Meanwhile, it will also delete the existing files, which is not what we want! We want to keep the existing files, without modifying them. This part is handled when the eventType corresponds to the UnitProducing value. There, we go through each class, and pretend they have been generated. That way, they will not be deleted if they exist. The method that does this is the AddToGeneratedFiles(path) method from the baseProducer class.
The Constants class simply contains 2 constants, used int the BuildOnlyResources class.
3. Adding options
We need to add a couple of options for our sub producer. The first is a boolean option that describes whether the sub producer is enabled or not. If not enabled, it will not be used during the generation. The second option is a boolean that describes whether the resources are produced or not.
4. Compiling the solution
We can now compile the solution in release mode and obtain a dll, called SubProducerResources.dll. In order to use that sub producer in our CodeFluent Entities model, we need to add this dll to the folder where CodeFluent Entities was installed, located at C:\Program Files (x86)\SoftFluent\CodeFluent\Modeler by default.
5. Displaying the subproducer in the modeler.
The last step is to be able to display that sub producer in the modeler. CodeFluent Entities looks at a config file located in: C:\Users\{user}\AppData\Roaming\CodeFluent.Modeler.Design\Custom.config. You need to create it because it does not exist. Its content needs to look like this:
<codeFluent.Modeler> <producerDescriptors> <producerDescriptor name="SubProducerResources" displayName="SubProducer Resources" category="My Custom Producers" typeName="SubProducerResources.BuildOnlyResources, SubProducerResources" /> </producerDescriptors> </codeFluent.Modeler>
6. Ready
Your sub producer is ready to be used! Open your CodeFluent Entities project, right-click on your BOM producer, and add a new sub producer. You should see your sub producer in the list:
Once added, it will appear under your BOM producer:
Here is what you are really looking for, the code for both BuildOnlyResources and Constants classes:
using System;
using System.CodeDom;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Xml;
using CodeFluent.Model;
using CodeFluent.Model.Common.Design;
using CodeFluent.Model.Design;
using CodeFluent.Producers.CodeDom;
using CodeFluent.Runtime.Utilities;
namespace SubProducerResources
{
[Category("Business Layer Producers")]
[DisplayName("SubProducer Resources")]
[Producer(Constants.CustomResourcesProducerNamespaceUri, Constants.CustomResourcesProducerNamespacePrefix)]
public class BuildOnlyResources : ICodeDomSubProducer
{
private CodeDomBaseProducer _baseProducer;
private CodeFluent.Producers.CodeDom.SubProducer _subProducer;
[Description("Determines if sub producer is enabled.")]
[Category("Configuration")]
[DefaultValue(true)]
[DisplayName("Is Enabled")]
[ModelLevel(ModelLevel.Normal)]
public virtual bool Enabled
{
get
{
return XmlUtilities.GetAttribute(Element, "enabled", true);
}
set
{
XmlUtilities.SetAttribute(Element, "enabled", value.ToString().ToLowerInvariant());
}
}
[Description("Determines if resources are produced.")]
[Category("Configuration")]
[DefaultValue(true)]
[DisplayName("Produce Resources")]
[ModelLevel(ModelLevel.Normal)]
public virtual bool ProduceResources
{
get
{
return XmlUtilities.GetAttribute(Element, "produceResources", true);
}
set
{
XmlUtilities.SetAttribute(Element, "produceResources", value.ToString().ToLowerInvariant());
}
}
public virtual void Initialize(CodeDomBaseProducer baseProducer, CodeFluent.Producers.CodeDom.SubProducer subProducer, IDictionary context)
{
_baseProducer = baseProducer;
_subProducer = subProducer;
baseProducer.CodeDomProduction += OnCodeDomProduction;
}
public virtual void Produce(IDictionary context, CodeCompileUnit unit)
{
}
public virtual void Terminate(IDictionary context)
{
}
private void OnCodeDomProduction(object sender, CodeDomProductionEventArgs e)
{
if (!Enabled)
return;
if (e.EventType == CodeDomProductionEventType.ResourcesProducing)
{
if (!ProduceResources)
{
e.Cancel = true;
}
}
if (e.EventType == CodeDomProductionEventType.UnitsProducing)
{
e.Cancel = true;
IEnumerable<CodeCompileUnit> units = (CodeCompileUnit[])e.Argument;
foreach (CodeCompileUnit unit in units)
{
FakeProduceUnit(unit);
}
}
// adapt to your needs
if (e.EventType == CodeDomProductionEventType.ConstantsProducing ||
e.EventType == CodeDomProductionEventType.SRProducing ||
e.EventType == CodeDomProductionEventType.BasicAuthenticationModuleProducing ||
e.EventType == CodeDomProductionEventType.BitsServerProducing ||
e.EventType == CodeDomProductionEventType.MembershipProviderProducing ||
e.EventType == CodeDomProductionEventType.MembershipUserProducing ||
e.EventType == CodeDomProductionEventType.ProfileProviderProducing ||
e.EventType == CodeDomProductionEventType.RoleProviderProducing)
{
e.Cancel = true;
}
}
private void FakeProduceUnit(CodeCompileUnit unit)
{
if (unit == null)
throw new ArgumentNullException("unit");
BaseType baseType = UserData.GetBaseType(unit); // get the type related to this unit, if any
if (baseType == null)
return;
// check if the type was to be produced or not
if (!_baseProducer.MustProduce(baseType, CodeFluent.Producers.CodeDom.Constants.ModelProducerNamespaceUri))
return;
Set set = baseType as Set;
if (set != null)
{
if (!_baseProducer.MustProduce(set.ItemEntity, CodeFluent.Producers.CodeDom.Constants.ModelProducerNamespaceUri))
return;
}
// determine the final target path where the file should have gone, and pretend it's been generated
string path = ((CodeDomProducer)_baseProducer).GetTargetPath(baseType);
path = _baseProducer.GetProductionTargetPath(baseType, path, false, false);
if (File.Exists(path))
{
_baseProducer.AddToGeneratedFiles(path);
}
}
public XmlElement Element
{
get
{
if (_subProducer == null)
throw new CodeFluentCodeDomProducerException(GetType().FullName);
return _subProducer.Element;
}
set
{
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SubProducerResources
{
public sealed class Constants
{
public const string CustomResourcesProducerNamespaceUri = "http://www.softfluent.com/codefluent/producers.customResources/2013/1";
public const string CustomResourcesProducerNamespacePrefix = "cfcr";
private Constants()
{
}
}
}
Vincent Patry
Exploring the CodeFluent Runtime: ChunkedMemoryStream
Today, on the series “Exploring the CodeFluent Runtime” we are going to take a look at the ChunkedMemoryStream class on the CodeFluent.Runtime.Utilities namespace.
This class allows you to manipulate a memory stream by “chunks”. This can be useful when you are dealing with memory streams big enough (85,000 bytes) to be allocated on the Large Object Heap (LOH).
The ChunkedMemoryStream can be used instead of the System.IO.MemoryStream (mscorlib.dll) to avoid memory fragmentation.
Let’s build a simple example in order to compare the use of a System.IO.MemoryStream against the CodeFluent.Runtime.Utilities.ChunkedMemoryStream.
Let’s say I want to load a file’s content in memory (big enough to sit on the LOH).
static void Main(string[] args)
{
FileStream fileSm = new FileStream(@"file_path", FileMode.Open);
Stream ms = new MemoryStream();
fileSm.CopyTo(ms);
ms.Close();
fileSm.Close();
System.Diagnostics.Debugger.Break();
}
When the Debugger breaks let’s explore the LOH:
We can see that the LOH size is (17184 + 41943056 + 83886096 = 125846336 bytes) and we easily distinguish a memory allocation for 2 byte arrays (perhaps some buffers used internally when copying the data from one stream to another).
Let’s now change only one line in our code example and use the CodeFluent.Runtime.Utilities.ChunkedMemoryStream.
static void Main(string[] args)
{
FileStream fileSm = new FileStream(@"file_path", FileMode.Open);
Stream ms = new CodeFluent.Runtime.Utilities.ChunkedMemoryStream();
fileSm.CopyTo(ms);
ms.Close();
fileSm.Close();
System.Diagnostics.Debugger.Break();
}
And let’s explore the LOH:
We now see that the LOH size is 17184 bytes and we cannot see any trace of a byte array.
Using the ChunkedMemoryStream we avoid allocating memory on the LOH when manipulating big streams.
Remeber that the CodeFluent Runtime Client is a free library that provides very useful and powerful helpers like:
- XML utilities
- IO utilities
- Type conversion helpers
- JSON utilities
- … and many other
You can easily install the CodeFluent Runtime Client from Nugget.
PM> Install-package CodeFluentRuntimeClient
Regards,
Pablo Fernadez Duran
Patch text files after code generation with CodeFluent Entities
CodeFluent Entities provides a large set of concepts and tools to generate code as custom as wanted. But, it may be a reason you need to modify the output produced by the CodeFluent Entities engine when there is not an option or a feature that allows you do that.
The Patch Producer is a producer that lets you “patch” text files using regular expressions. You can find the Patch Producer under the Utility Producers category.
Path: can be a directory path or a file path. If relative, it is based from the directory containing the project root part.
File Search Pattern: is a file filter expression. Only used if “path” is a directory.
Search Pattern: a regular expression matching groups.
Replace: a key=value pair list separated by the “Replace Separator Character”.
You can use the default namespace in the path attribute using the syntax {1:DefaultNameSpace}
Example 1
CodeFluent Entities provides a “tracking” feature.
In most of the cases the CodeFluentUser.Name is of the form “Domain\UserName” and let’s say we only want to store in the database the “UserName” without the “Domain” (ie. The CodeFluentUser.UserName).
In my case I have a CodeFluent Entities project with a Business Object Model (BOM) producer and a SQL Server persistence producer. The BOM generated files are stored in a class library project having as name the default namespace.
So, I need to search all files matching “ *.cs ” in my BOM project:
And make the replacement using the regular expression:
,\s*persistence\.Context\.User\.(?<name>Name)\s*\)
And replace the matched value in the group name “name” by “UserName”:
If I build my CodeFluent Entities, now I have:
Example 2
CodeFluent Entities adds some information on each generated file about the generation itself. For example, for SQL files:
Let’s say we want to add the name our company within this information, something like “CodeFluent Generated for SoftFluent […]”
We add a new “Patch” producer.
As you can see, I store my SQL files in a folder named “SQL” in the same location as my BOM generated files (cf. example 1).
We build the CodeFluent Entities project and now we have:
Have fun.
Regards,
Pablo Fernandez Duran
Using the Cache Sub-Producer
CodeFluent Entities provides an integrated cache system for the Business Object Model (BOM) layer. The Object Model Cache (OMC) is not enabled by default. To add the cache feature to your BOM you need to first add a Cache sub producer.
If you set the “Is Default Enable” attribute to “True” the cache feature will be enabled for all the entities in your model. You can also decide to enable or not the cache feature by entity or by method.
As you can see in the image above, you can independently specify whether you want to enable the cache feature for Collections or not by changing the value of the “Is Collection Enabled” attribute.
If you enable the cache feature, when calling a “LoadXXX” method (ex. Load, LoadById…) on your entity will make that a cache verification is performed before trying to load the data from the data source (SQL server for example).
If you want to bypass the cache you can call the “NoCacheLoadXXX” method (ex. NoCacheLoad, NoCacheLoadById…). When saving or deleting an instance of an entity, the cache is cleared (for that entity) and you can clear manually the cache calling the “CacheClear” method on an entity (public static method).
You may considerate some points when using a Cache system:
- Complexity will be added to your application.
- Unexpected behaviors may appear if not using it correctly.
- The Object Model Cache provided by default is an in-memory cache, so it cannot be shared between servers.
- It is not interesting to use a Cache system if the cached data changes too often. It’s best to cache immutable or almost immutable data.
An example scenario when the Object Model Cache feature could be useful may be when storing “referential” data on a data base or data that does not change too often.
CodeFluent entities provides three types of Cache implementations:
- Simple Cache Manager, based on the ASP .NET cache (that can be used outside of ASP.NET) (CodeFluent.Runtime.Caching.SimpleCacheManager, CodeFluent.Runtime).
- Simple Localized Cache Manager, a sub-class of the Simple Cache Manager that can manage localized keys (CodeFluent.Runtime.Caching.LocaleCacheManager, CodeFluent.Runtime)
- Enterprise Library Cache Management, you must install the Enterprise Library in order to use it (CodeFluent.Runtime.Caching.EnterpriseLibraryCacheManager, CodeFluent.Runtime).
You can specify the type of cache you want to use on the “Runtime Cache Type Name” attribute (the full type name). You can use a different cache systems by scope (entity, method).
You can use a different or custom type of cache not provided by CodeFluent Entities, you only need to implement the CodeFluent.Runtime.Caching.ICacheManager interface.
Finally, you can disable the cache feature by configuration (only for the Simple Cache Manager and the Simple Localized Cache Manager), for a testing or development environment for example. You only need to add the following code to your app.config or web.config file:
<appSettings> <add key="CodeFluent.Runtime.Caching.SimpleCacheManager.Enabled" value="false"/> </appSettings>
Regards,
Pablo Fernandez Duran



























