Archive
[Pet Shop Reloaded] The Application
The Pet Shop Reloaded is a sample e-commerce web application. Users will be able to browse a nice set of animals by category, add them to their cart or wish list, and finish their purchase by log in or register to the application.
Functional context
Users first arrive to the home page where are displayed some random animals to discover.
On the top of the page users can perform actions like:
- See their cart.
- Register.
- Log in/Log off (if connected).
- Wish list (if connected).
- Account information (if connected).
- Search animals by keywords.
Users can browse animals by category.
When selecting an animal, are displayed all the different kinds of this animal with some details like the quantity remaining and the price.
Users can then add the desired animal to their cart or to their wish list (if logged in).
The cart page contains the list of animals to purchase by quantity.
When the user checks out, he has to confirm his billing and shipping addresses, provide his payment and confirm his order.
If the user is logged in, he can add animals to his wish list and manage it.
Users can manage at any time their account information.
Technical context
The SoftFluent Pet Shop Reloaded will be developed as a web solution using:
- .NET 4.5.
- C# 5.
- ASP .NET MVC 4.
- SQL Server 2008 R2 (the 2012 version can be used as well).
- Visual Studio 2012.
The CodeFluent version
The CodeFluent Entities PetShop version will use the CodeFluent build 61214.707.
We will build the CodeFluent Entities model using the CodeFluent Entities Designer. This means that all the aspects related to the model will be implemented within the CodeFluent Model Designer, like:
- Data validation and custom business rules.
- Custom data access methods (stored procedures).
- Custom and extra attributes.
- Instances (data used to fill the database, useful to start with an application containing data).
There will be 2 producers to generate the Business Object Model layer (BOM) and the Persistence layer:
- The BOM producer will generate our .NET/C# classes, these classes contain all the logic that we have defined in our model (Validation, Rules, CRUD methods, custom data access methods…).
- The SQL Server producer will produce (and execute) SQL scripts to generate or update our database. CodeFluent Entities provides a “SQL diff engine” smart enough to update our database schema without losing our data.
On the MVC application we will directly use the BOM to manipulate and bind our models.
The Entity Framework version
The Entity Framework PetShop application will be built with the Entity Framework version 5 provided out-of-the-box with Visual Studio 2012.
We will use the Model First approach to design our model and we are going to use the built in templates (.tt templates) to generate our .NET/C# classes.
For validation and custom rules we may need to do some extra work, this will be explained in a blog post dedicated to Validation and Rules.
The persistence layer will be generated using the SQL code generated by the Entity Framework.
We will use essentially LINQ queries to retrieve data and the generated model will be used directly on the MVC application.
On the next blog post we are going to show how to start with CodeFluent Entities and Entity Framework (installation) before starting using the model designers.
Remember that 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
[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. ![]()
- The Application.
- Getting started.
- The Model Designers.
- …
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
Remove the current date and time to generated files
CodeFluent Entities adds some information to generated files every time a code production is run.
This information contains general information (for all producers) and specific information (for each producer):
- The CodeFluent Entities Build version.
- The current date and time.
- The Runtime version.
- The Target version.
- The Culture.
- The Encoding.
- - …
You might want to avoid CodeFluent Entities to add some of this information to generated code.
For example, each time a code production is made almost all generated files will have a new “generation date” even if the generated code is the same.
When using a source control system you will need to checkin/commit every single file even if only the generation date has changed. This can lead to conflicts and unnecessary merges.
Well, CodeFluent Entities provides an option to remove the “generation date and time” when running producers.
This options is found in the “advanced properties tab” at the project level (right click on the CodeFluent Entities project > Properties).
Set the defaultProducerProductionFlag flag to RemoveDiffs to avoid having the “date and time” on generated files.
Since the CodeFluent Entities build 702 (march 2013) the RemoveDiffs production flag option now also removes the Runtime Version value added to generated files.
Regards,
Pablo Fernandez Duran
Using the LINQ to SQL Sub-Producer
CodeFluent Entities gives you the possibility to make your generated Business Object Model (BOM) compatible with the LINQ to SQL data access infrastructure.
CodeFluent Entities ships a LINQ to SQL producer, that is in fact a Sub-Producer of the Business Object Model (BOM) Producer.
Let’s start by setting a model to work with.
For this post I will create a very simple model. A “Person” entity who has zero or more “Pets” of a given kind.

Pet management model
I will also add Class Library project to my solution so I can store the generated code by CodeFluent Entities.
I will add a Persistence producer (SQL Server) and a Business Object Model Producer. I will set the Target Directory to my Class Library project for both producers.
Now I can add my Linq-To-Sql producer. As said before, this producer is a Sub-Producer of the BOM Producer, so I have to add it to the BOM Producer.

Add Sub-Producer

LINQ to SQL Sub-Producer
As you can see, there is no configuration required for this Sub-Producer.
We need to set the “Default Entity Tracking Mode” to “None” at the project level to avoid any problem with the LINQ to SQL query provider.

Default Entity Tracking Modes
Let’s build our CodeFluent Entities project, and open a BOM class so we can see what has been generated.

LINQ to SQL attributes
We now see that our class has been decorated with LINQ to SQL attributes. We also see that the “System.Data.Linq” namespace is not defined. To fix that we need to add a reference to the “System.Data.Linq” assembly in our BOM project.
We have now a LINQ to SQL compliant BOM.
Let’s test it using LINQ to SQL.
For that I will add a simple Console application. Then I add a reference to my BOM project, to the CodeFluent.Runtime assembly and to the System.Data.Linq assembly. And add the right application configuration.
We will use the DataContext class provided by the LINQ to SQL infrastructure to manipulate data (insert, delete, update and read). And we can retrieve the connection string from the CodeFluentContext class.
string connectionString = CodeFluentContext.Get(PetsManagement.Constants.PetsManagementStoreName).Persistence.ConnectionString;
using (DataContext context = new DataContext(connectionString))
{
}
Let’s start by adding some data to our database:
string connectionString = CodeFluentContext.Get(PetsManagement.Constants.PetsManagementStoreName).Persistence.ConnectionString;
using (DataContext context = new DataContext(connectionString))
{
Person bart = new Person { Name = "Bart" };
Pet bartsDog = new Pet { Name = "Santa's Little Helper", Age = 2, Kind = PetKind.Dog };
bartsDog.Owner = bart;
Pet bartsCat = new Pet { Name = "Snowball II", Age = 3, Kind = PetKind.Cat };
bartsCat.Owner = bart;//not true, is Lisa
Person pablo = new Person { Name = "Pablo" };
Pet pablosDog = new Pet { Name = "Shiny", Age = 17, Kind = PetKind.Dog };
pablosDog.Owner = pablo;
Pet pablosDog2 = new Pet { Name = "Vanilla", Age = 10, Kind = PetKind.Dog };
pablosDog2.Owner = pablo;
Person ferb = new Person { Name = "Ferb" };
Pet ferbsPet = new Pet { Name = "Perry", Age = 32, Kind = PetKind.Platypus };
ferbsPet.Owner = ferb;
context.GetTable<Person>().InsertAllOnSubmit(new[] { bart, pablo, ferb });
context.GetTable<Pet>().InsertAllOnSubmit(new[] { bartsDog, bartsCat, pablosDog, pablosDog2, ferbsPet });
context.SubmitChanges();
}
Now let’s retrieve all the pets grouped by “Pet kind”.
string connectionString = CodeFluentContext.Get(PetsManagement.Constants.PetsManagementStoreName).Persistence.ConnectionString;
using (DataContext context = new DataContext(connectionString))
{
var petsByKind = from pet in context.GetTable<Pet>()
group pet by pet.Kind into gr
select gr;
foreach (IGrouping<PetKind, Pet> kindGroup in petsByKind)
{
Console.WriteLine("----" + kindGroup.Key + "----");
foreach (Pet pet in kindGroup)
{
Console.WriteLine(pet.Name + " : " + pet.Owner.Name);
}
}
}
The result is:

Pets grouped by kind
Let’s now delete a cat named “Snowball II” which owners name is “Bart”.
string connectionString = CodeFluentContext.Get(PetsManagement.Constants.PetsManagementStoreName).Persistence.ConnectionString;
using (DataContext context = new DataContext(connectionString))
{
Pet petToDelete = (
from person in context.GetTable<Person>()
where
person.Name == "Bart"
from pet in person.Pets
where
pet.Kind == PetKind.Cat &&
pet.Name == "Snowball II"
select pet
)
.FirstOrDefault();
if (petToDelete != null)
{
context.GetTable<Pet>().DeleteOnSubmit(petToDelete);
context.SubmitChanges();
}
}
Thanks to the LINQ to SQL Sub-Producer we can use the LINQ to SQL infrastructure with our BOM, but there are several limitations and several concepts/features that can be done by CodeFluent Entities and not supported by LINQ to SQL: The CodeFluent Entities model is richer than LINQ to SQL (rules, validation, aspects, advanced relations, automatic tracking, cache, circular dependencies, multi-databases…).
Regards,
Pablo Fernandez Duran





































