Archive

Author Archive

Target Name Transformation aka TNT

October 10, 2014 Leave a comment

CodeFluent Entities allows you to write RAW methods. Using the name of a table or a column in a RAW method is not safe. Indeed CodeFluent Entities allows to define its own naming convention. So if you write the name of a column in a raw method and then you change the naming convention of your project, your method won’t work anymore.

To handle this case, CodeFluent Entities introduce Target Name Transformation (aka TNT). In a Raw method you can refers to a column by using for example “$Customer::DateOfBirth$”. This will be replaced by CodeFluent Entities by the name of the column corresponding to the property “DateOfBirth” of the entity “Customer”.

TNT supports the following syntaxes:

  • $[EntityName]$ corresponds to the table name,
  • $[PropertyName]$ corresponds to the property name,
  • $[EntityName]::[PropertyName]$ corresponds to the column name,
  • $[EntityName]:[ViewName]$ corresponds to the view name,
  • $[EntityName]:[ViewName]:[PropertyName]$ corresponds to a column name in the defined view,
  • $[Namespace].[EnumerationName].[EnumerationValue]$ corresponds to the enumeration value of an enumeration declared in the model.

We already talk about all of this. So today I’ll show you more.

When you write “$[EntityName]::[PropertyName]$”, CodeFluent Entities find the property and write its persistence name. But you can also specify a format by using curly brackets. Format allows you to navigate in the CodeFluent Entities API and get the desired value. Here’s some examples:

$Customer{Columns}$

[Customer].[Customer_Id],[Customer].[Customer_Name],[Customer].[Customer_DateOfBirth],
[Customer].[_trackLastWriteTime],[Customer].[_trackCreationTime],
[Customer].[_trackLastWriteUser],[Customer].[_trackCreationUser],
[Customer].[_rowVersion] 

$Customer:CustomView{Columns}$

[vCustomerCustomView].[Customer_Id],[vCustomerCustomView].[Customer_Name],
[vCustomerCustomView].[_rowVersion],[vCustomerCustomView].[_trackCreationTime],
[vCustomerCustomView].[_trackLastWriteTime],[vCustomerCustomView].[_trackCreationUser],
[vCustomerCustomView].[_trackLastWriteUser]

$Customer{TrackCreationUserColumn.FullName}$

[Customer].[_trackCreationUser]

$Customer{TrackLastWriteUserColumn.FullName}$

[Customer].[_trackLastWriteUser]

$Customer{TrackCreationTimeColumn.FullName}$

[Customer].[_trackCreationTime]

$Customer{TrackLastWriteTimeColumn.FullName}$

[Customer].[_trackLastWriteTime]

$Customer{RowVersionColumn.FullName}$

[Customer].[_rowVersion]

$Customer{TypeNameColumn.FullName}$

[Customer].[_typeName]

$Customer{Schema}$

Sample

$Customer{Entity.Properties.Count}$

3

$Customer{Columns[0].Name}$

Customer_Id

$Customer{Entity.Properties["Name"].Column.Name}$

Customer_Name

$FirstName{Name}$

FirstName

$Customer::Name{DefaultValue}$

John Doe

$Customer::Id{FullPersistenceName}$

[Customer].[Customer_Id]

$Customer:CustomView:FirstName{Expression}$

FirstName

$Customer{Procedures["Customer_Load"].FullName}$

[Customer_Load]

To find all possible formats, open Visual Studio Object Browser (Menu / View / Object Browser), and add “C:\Program Files (x86)\SoftFluent\CodeFluent\Modeler\CodeFluent.Model.dll” and look at properties of classes:

  • CodeFluent.Model.Persistence.Table
  • CodeFluent.Model.Property
  • CodeFluent.Model.Persistence.View
  • CodeFluent.Model.ViewProperty
  • CodeFluent.Model.Enumeration
  • CodeFluent.Model.EnumerationValue

If you can’t figure how to get a specific information from your model, please ask your question on the forum.

Happy TNTing,

The R&D Team

CodeFluent Entities and ComponentOne

October 6, 2014 Leave a comment

CodeFluent Entities generates code which can be used easily with many third party component providers. We already show before how to use CodeFluent Entities with Syncfusion. Today we’ll see how easy it is to work with ComponentOne (C1) WPF components!

The sample application displays a list of users and their contacts using a ComponentOne DataGrid. Additionally you can export user list to Excel.

The solution contains 4 projects:

The CodeFluent Entities model is very simple:

The email has a validation rule to ensure you can only save a user with an invalid email address to the database.

The relation between User and Contact is configured to save contacts after user. This means that when you call User.Save, associated contacts are also saved. This functionality is very useful in a master-detail view as we are creating!

Now we can create the WPF application. Here’s the main part of the XAML:

<Window.Resources>
<!-- Convert blob to image -->
<design:BinaryLargeObjectValueConverter2 x:Key="BlobConverter"/>
</Window.Resources>

<Grid>

<c1:C1DataGrid x:Name="DataGrid" ItemsSource="{Binding}" AutoGenerateColumns="False" RowDetailsVisibilityMode="VisibleWhenSelected">
  <c1:C1DataGrid.Columns>
    <c1:DataGridImageColumn Binding="{Binding Photo, Converter={StaticResource BlobConverter}}" Header="Photo" IsReadOnly="True" />
    <c1:DataGridTextColumn Binding="{Binding FirstName}" Header="First name" />
    <c1:DataGridTextColumn Binding="{Binding LastName}" Header="Last name"  />
    <c1:DataGridTextColumn Binding="{Binding Email}" Header="Email"  />
    <c1:DataGridBoundColumn Binding="{Binding Contacts.Count}" Header="Contacts" IsReadOnly="True" />
  </c1:C1DataGrid.Columns>

  <!-- Handle validation using IDataErrorInfo (this will validate the Email property) -->
  <c1:C1ValidationBehavior.ValidationBehavior>
    <c1:C1ValidationBehavior/>
  </c1:C1ValidationBehavior.ValidationBehavior>

  <c1:C1DataGrid.RowDetailsTemplate>
    <DataTemplate>
      <StackPanel Orientation="Vertical">
        <TextBlock Text="Contacts" FontSize="14"/>

        <c1:C1DataGrid ItemsSource="{Binding Contacts}" AutoGenerateColumns="False" BeginningNewRow="C1DataGrid_BeginningNewRow">
          <c1:C1DataGrid.Columns>
            <c1:DataGridTextColumn Binding="{Binding FirstName}" Header="First name" />
            <c1:DataGridTextColumn Binding="{Binding LastName}" Header="Last name" />
          </c1:C1DataGrid.Columns>
        </c1:C1DataGrid>
      </StackPanel>
    </DataTemplate>
  </c1:C1DataGrid.RowDetailsTemplate>
</c1:C1DataGrid>

<Button Grid.Row="1" HorizontalAlignment="Left" Click="ButtonExportToExcel_OnClick">Export Users to Excel</Button>
<Button Grid.Row="1" HorizontalAlignment="Right" Click="ButtonSaveAll_OnClick">Save all</Button>

</Grid>

When the window is opened, we load all users:

private readonly UserCollection _userCollection;

public MainWindow()
{
  // Load all users and bind them to the grid
  _userCollection = UserCollection.LoadAll();

  this.DataContext = _userCollection;
}

To save all users and their contacts, we have to call SaveAll method:

private void ButtonSaveAll_OnClick(object sender, RoutedEventArgs e)
{
   // Thanks to the cascade save, contacts are also saved
   _userCollection.SaveAll();
}

When a contact is added, we have to set its User property with the selected user:

private void C1DataGrid_BeginningNewRow(object sender,
DataGridBeginningNewRowEventArgs e)
{
  var contact = e.Item as Contact;

  if (contact == null)
    return;

  var user = DataGrid.CurrentRow.DataItem as User;

  if (user != null)
  {
    contact.User = user;
  }
}

Finally we can export user collection to Excel:

private
void ButtonExportToExcel_OnClick(object sender, RoutedEventArgs e)
{
  DataGrid.Save("export.xlsx", FileFormat.Xlsx);
}

That’s it. With only a few lines of code, CodeFluent Entities and ComponentOne you can create a fully functional application.

The code sample is available on our GitHub repository: https://github.com/SoftFluent/CodeFluent-Entities/tree/master/Samples/SoftFluent.Samples.ComponentOne

Happy componenting,

The R&D Team

Getting started with the Blob Handler

October 6, 2014 Leave a comment

In ASP.NET, if you need to display a blob (Binary Large Object) such as an image, a video or a file, you’ll need to provide an URL to your display control. When storing blobs in database, a standard practice is to create a web page such as a blob.aspx to which you provide the blob’s id as parameter and which the page will load and display so that you can set your display control’s source to that URL.

Actually, CodeFluent Entities automatically generates a HTTP Handler which does all the work described before: thanks to it you’ll retrieve an URL pointing to your blob and which you’ll be able to use in your display controls.

To use it you need to register it in your web.config file as:

<system.web>
    <httpHandlers>
      <add verb="GET" path="blobhandler.ashx" 
type="<DefaultNamespace>.Web.HttpHandler, <DefaultNamespace>"/>
    </httpHandlers>
</system.web>

Or

<system.webServer>
    <httpHandlers>
      <add name="blobhandler" verb="GET" path="blobhandler.ashx"
type="<DefaultNamespace>.Web.HttpHandler, <DefaultNamespace>" />
    </httpHandlers>
</system.webServer>

Blob handler output types

 

The blob handler allows to get blobs in different manners to fit with common usages.

  • Raw: Use for downloading a File
  • Image: Use for displaying an Image

  • Thumbnail: Display a thumbnail of the Image (you can specify the desired height and width)


  • FileExtension: Display the File icon base on its extension (the same icon as in Windows Explorer)

  • FileExtensionSmall: Display the small Fileicon base on its extension (the same icon as in Windows Explorer)

To build the URL, you can use:

  • HttpHandler.BuildUrl(…)
  • BaseBinaryLargeObject.BuildHttpHandlerUrl(…)
  • ASP.Net controls: BinaryLargeObjectControl, BlobControl and BinaryLargeObjectField (located in CodeFluent.Runtime.Web)

For instance:

customer.Photo.BuildHttpHandlerUrl(BinaryLargeObjectUrlType.Raw)
customer.Photo.BuildHttpHandlerUrl(BinaryLargeObjectUrlType.Image)

Securing the blob handler

 

If you want to prevent some users to access the blob handler and so download files, you can write your own validation logic:

  • Add a partial class “HttpHandler.partial.cs”:

  • Then override the ResponseWriteBlob method and add your logic:
partial class HttpHandler
{
protected override bool ResponseWriteBlob(CodeFluent.Runtime.BinaryServices.BinaryLargeObject blob)
  {
    // Only administrators can access the blob handler
    return this.CodeFluentContext.User.IsInRole("Administrator");
  }
}

Server and client cache

 

Moreover blobs can be cached on the server and on the client to relieve the database. This feature is activated by default.

  • Server cache: When loading a blob property using CodeFluent Entities, it actually loads it from the database the first time and stores it on the disk; consequently, next calls won’t load it back from database anymore, unless a modification was done on the blob which will reload it and update the cache.
  • Client cache: Usage of the “Last-Modified” and “If-Modified-Since” http headers so the client download blobs only once.

Read more details about blob caching at http://blog.codefluententities.com/2011/11/09/codefluent-entities-blob-cache/

Happy storing,

The R&D Team

Member Format Expression

September 29, 2014 Leave a comment

Using CodeFluent Entities, you can use “Member Format Expressions” to customize the way names of entities and properties are formatted. We’ve already written before about the member format expression:

Today I’ll share the property format expression I use everyday. By default entities display property name and optionally type name:

Let’s create a new property format expression. Click the “Property Format” menu Item / “Choose”. Click the “Add New” button and copy the following format expression:

<if condition=IsEntityDisplay>-> </if> <if condition=IsNullable>({Name})<else />{Name}</if> : {DisplayTypeName} <if condition=”‘true’=Element.GetAttribute(‘localizable’,’http://www.softfluent.com/codefluent/patterns/localization/2008/1&#8242;)”>(Localizable)</if> <if condition=Relations.Count>({CascadeDelete})</if>

Now entities look like:

  1. The icon indicates the property is a member of the primary key
  2. Parentheses indicate the property is nullable
  3. “(Localizable)” indicates the property is localizable when using the Localization aspect
  4. “->” indicates the property is the entity display name
  5. The icon indicates the property type is an enumeration
  6. “(None)”, “(Before)” or “(After)” indicates the selected Cascade Delete option of the relation
  7. “*” and the infinite symbol indicate the property type is a collection

Thanks to the extensibility of the CodeFluent Entities modeler you can customize your working environment to fit your need. With this property member format, you visualize lots of information about your model in a breeze. Can you do that without CodeFluent Entities?

Happy formatting !

The R&D Team

Export your model as image

September 26, 2014 Leave a comment

Do you know that it’s possible to save the current Surface display in an image file ? It’s the easy way to share your model with someone.

You just need to right-click somewhere in the selected surface. Then you’ll see a new contextual menu with the following command:

Many formats are supported: PNG, BMP, GIF, WDP, JPG, and TIFF.

Here are some examples:

Happy exporting,

The R&D Team.

How to enable Intellisense for CodeFluent Entities runtime configuration?

September 16, 2014 Leave a comment

CodeFluent Entities generated code can be configured using the application configuration file (App.config or web.config):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="Sample"
     type="CodeFluent.Runtime.CodeFluentConfigurationSectionHandler,
           CodeFluent.Runtime" />
  </configSections>
  <Sample connectionString="<connection string>" useDateTime2="true" />
</configuration>

The configuration section is describe in the documentation: http://www.softfluent.com/documentation/BOM_ApplicationConfiguration.html.

This section is not known by Visual Studio, so you may have the following message:

ErrorXML

In fact Visual Studio doesn’t have an XML schema for this section and so it can’t validate it. At the same time we cannot provide a generic schema as the section name is Project specific. So the solution is to use The Template producer  which will generate the XML  schema based on the information from your Project.

  1.  

  2. Add a template producer

     

  3. Build the model
  4. Open the app.config or web.config file and add the following xml attributes (replace <Default namespace> by your project default namespace)

<configuration

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;

xsi:schemaLocation=”http://www.softfluent.com/<Default Namespace>/CodeFluentConfiguration.xsd CodeFluentConfiguration.xsd”>

You should now have auto-completion of the CodeFluent Entities configuration section.

binary services

 

 

 

 

 

 

 

Note: this xml schema includes only most common settings. If you think we forgot some useful settings, please leave a comment.

Happy configuration,

The R&D Team

Localize Dynamic Resources using an Aspect

September 15, 2014 Leave a comment

CodeFluent Entities handles static localization with the message concept. Static resources refer to all those UI messages that will never change throughout your application’s life-time: labels, error messages, information messages, titles, button texts, tool tips, etc.

CodeFluent Entities (Personal and Ultimate Edition) also handles dynamic localization out of the box. Dynamic resources refer to localized data created at runtime. For instance a web shop could have an international catalog in several languages, and this catalog should be displayed in a specific language depending on the users’ language (i.e. culture in .Net). Administrators add, remove or modify items from this catalog during the application’s life-time. Thus, administrators of the catalog will need to create catalog items with labels in several languages in order to support internationalization.

Let’s see how to use dynamic localization with CodeFluent Entities.

First, create an entity:

Then add the localization aspect:

Now we have to indicate the Description property is localizable:

That’s all. Yes you read that right! As a bonus you can define localized instances in the model:

Let’s generate the code and see what is generated:

The database contains two tables

The product table contains non-localized columns and the default value of the localized columns. The default value is used when no translation exists for one culture while loading row.

The table “ProductLocalized” contains translations:

The BOM is edited automatically but you can use it the same way as if there is no dynamic localization. Save and Load method use Thread.CurrentUICulture to know which description to load or save.

// First we create a product with an English description
Thread.CurrentThread.CurrentUICulture = new CultureInfo(1033);
Product product = new Product();
product.Name = "Sample product";
product.Description = "A description in English";
product.Save();

// We create a French description.
Thread.CurrentThread.CurrentUICulture = new CultureInfo(1036);
product.Description = "Une description en français";
product.Save();

// We can also add localization by using the static method SaveLocalizedValues
Product.SaveLocalizedValues(product, 1033, isDefault: true, description: "A description in English");

// Load products with an English description
Thread.CurrentThread.CurrentUICulture = new CultureInfo(1033);
var productsEn = ProductCollection.LoadAll();

// Load products with a French description
Thread.CurrentThread.CurrentUICulture = new CultureInfo(1036);
var productsFr = ProductCollection.LoadAll();

// Load products with a German description =&gt; There is no German description so the default value is used
Thread.CurrentThread.CurrentUICulture = new CultureInfo(1031);
var productsDe = ProductCollection.LoadAll();

Localizing Dynamic Resources is very easy with CodeFluent Entities and the <a href="http://www.softfluent.com/documentation/BOM_LOC_DynamicResources.html">localization aspect</a>. Good news, this aspect is available out of the box!

Happy localizing,

The R&D Team

Categories: Aspects
Follow

Get every new post delivered to your Inbox.

Join 51 other followers