CodeFluent Entities and SignalR

November 21, 2014 Leave a comment

ASP.NET SignalR is a new library for ASP.NET developers that makes it incredibly simple to add real-time web functionality to your applications. What is “real-time web” functionality? It’s the ability to have your server-side code push content to the connected clients as it happens, in real-time.

Let’s see how easy it is to use CodeFluent Entities with SignalR! This post introduces SignalR development by using CodeFluent Entities and showing how to create an application that shares the state of an CodeFluent entity (Customer) with other clients in real time.

Setting up the solution

The solution contains 4 projects:

  • The CodeFluent Entities model
  • A class project to contains the generated Business Object Model
  • The SignalR server (Console application)
  • The SignalR client (WPF application)

The CodeFluent Entities model
The model is very simple, just one entity:

To generate the server code we add the SQL Server Producer and the Business Object Model producer.

SignalR uses Json.NET to serialize object. The way this library finds a way to serialize an object is weird and does not works with generated object by default because of the following attribute:

[TypeConverterAttribute(typeof(CodeFluent.Runtime.Design.NameTypeConverter))]

So we have to remove it so the object is serialize correctly:

To generate the client object we add the Service Model sub producer (with the same setting as above):

Don’t forget to remove runtime design attributes:

Finally the model project looks like:

The SignalR server

The server is a Console application. First we add the “Microsoft.AspNet.SignalR.SelfHost” nuget package.

We can register the SignalR server:

class Program
{
    static void Main()
    {
        using (WebApp.Start<Startup>("http://localhost:12345"))
        {
            Console.WriteLine("Server started");
            Console.ReadKey();
        }
    }
}

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        HubConfiguration hubConfiguration = new HubConfiguration();
        hubConfiguration.EnableDetailedErrors = true;
        app.MapSignalR(hubConfiguration);
    }
}

Now we can create the Customer hub:

public class CustomerHub : Hub
{
    public IEnumerable<Customer> Get()
    {
        return CustomerCollection.LoadAll();
    }

    public bool Save(Customer customer)
    {
        bool save = Customer.Save(customer);
        if (save)
            Clients.All.Saved(customer); // Notify clients

        return save;
    }

    public bool Delete(Customer customer)
    {
        bool delete = Customer.Delete(customer);
        if (delete)
            Clients.All.Deleted(customer.Id); // Notify clients

        return delete;
    }
}

The generated Business Object Model is easy to use with any technology J.

The SignalR Client

The client is a WPF application. First we need to add the “Microsoft.AspNet.SignalR.Client” nuget package.

The project already contains generated class from the model so we don’t need to create a Customer class:

Let’s create the XAML:

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal" Grid.Row="0">
            <Button Content="Load customers" Click="ButtonLoadCustomers_OnClick" Margin="5"/>
        </StackPanel>

        <DataGrid Grid.Row="1" x:Name="DataGrid" AutoGenerateColumns="False" RowEditEnding="DataGrid_RowEditEnding">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding EntityKey, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="Entity Key"/>
                <DataGridTextColumn Binding="{Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="First Name"/>
                <DataGridTextColumn Binding="{Binding LastName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="Last Name"/>

                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Command="Delete" Content="X" Click="ButtonDelete_OnClick" DataContext="{Binding}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>

Create the connection to the server and register callbacks:

private async Task<bool> EnsureProxy()
{
    if (HubProxy != null)
        return true;

    Connection = new HubConnection(ServerUri);
    HubProxy = Connection.CreateHubProxy("CustomerHub");

    // Register callbacks
    HubProxy.On<Customer>("Saved", OnCustomerSaved);
    HubProxy.On<Guid>("Deleted", OnCustomerDeleted);
    try
    {
        await Connection.Start();
        return true;
    }
    catch (HttpRequestException)
    {
        Connection.Dispose();
        Connection = null;
        MessageBox.Show("Unable to connect to server: Start server before connecting clients.");
        return false;
    }
}

Handle events:

private void OnCustomerDeleted(Guid id)
{
    var customerCollection = DataGrid.ItemsSource as CustomerCollection;
    if (customerCollection != null)
    {
        customerCollection.Remove(id);
    }
}

private void OnCustomerSaved(Customer customer)
{
    var customerCollection = DataGrid.ItemsSource as CustomerCollection;
    if (customerCollection != null)
    {
        var c = customerCollection[customer.Id];
        if (c != null)
        {
            customer.CopyTo(c, true); // Update existing customer
        }
        else
        {
            customerCollection.Add(customer); // Add new customer
        }
    }
}

Handle UI events (load, edit, delete):

private async void ButtonLoadCustomers_OnClick(object sender, RoutedEventArgs e)
{
    if (!await EnsureProxy())
        return;

    var customers = await HubProxy.Invoke<CustomerCollection>("Get");
    if (customers == null)
        customers = new CustomerCollection();

    BindingOperations.EnableCollectionSynchronization(customers, _lock);
    DataGrid.ItemsSource = customers;
}

private async void DataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
    if (e.Cancel)
        return;

    var result = await HubProxy.Invoke<bool>("Save", e.Row.Item);
}

private async void ButtonDelete_OnClick(object sender, RoutedEventArgs e)
{
    var customer = ((Button)sender).DataContext as Customer;
    if (customer == null)
        return;

    if (!await EnsureProxy())
        return;

    var result = await HubProxy.Invoke<bool>("Delete", customer);
}

The Business Object Model and the Service Object Model are very easy to use with any .NET technologies such as SignalR or Web API.

If your SignalR API is as simple as the one we create, you can automate its creation with templates.

The code sample is available on our GitHub repository.

Happy Coding,

The R&D Team

Visual Studio Community 2013

November 17, 2014 Leave a comment

Visual Studio Community 2013 is a new, full-featured, and FREE addition to the Visual Studio product lineup.

We are thrilled to announce that CodeFluent Entities runs great on it!

Visual Studio 2013 Community Edition

You can learn more about the new features of Visual Studio Community 2013 here:

You can download the latest version of CodeFluent Entities here, or update your version using the Licensing tool. Remember that you can follow the latest new features and bug fixes of CodeFluent Entities subscribing to this RSS.

Happy downloading,

The R&D Team

Categories: News Tags: ,

Exploring the CodeFluent Runtime: Convert utilities

November 3, 2014 Leave a comment

Today, on the series Exploring the CodeFluent Runtime,  we are going to explore the useful ConvertUtilities class from the CodeFluent.Runtime or CodeFluent.Runtime.Client assembly.

First of all you need to reference the dll in your project and include the directive as follow:

using CodeFluent.Runtime.Utilities;

The CodeFluent.Runtime is a part of the CodeFluent Entities product or you can download the following nuget package.

ChangeType

Returns an instance of type T whose value is equivalent to a specified input object. If an error occurs, a computed default value of type T will be returned.

var convert1 = ConvertUtilities.ChangeType<int>("42");
// –> 42
ConvertUtilities.ChangeType<bool>("yes"); // –> True
ConvertUtilities.ChangeType<bool>("y"); // –> True
ConvertUtilities.ChangeType<bool>("1"); // –> True
ConvertUtilities.ChangeType<CultureInfo>(1036); // –> CultureInfo("fr-fr")
ConvertUtilities.ChangeType("10/30/2014", DateTime.Now, new CultureInfo("en-US")); // –> 'October  30<sup>Th</sup> 2014' fr-FR
ConvertUtilities.ChangeType("Monday, Tuesday Wednesday | 8", DayOfWeek.None); // –>  Monday | Tuesday | Wednesday | Thursday
// Available separators: space, comma, pipe

SetCurrentThreadCulture

Sets the current thread culture. Handles integer values as lcid (http://msdn.microsoft.com/en-us/goglobal/bb964664.aspx)

ConvertUtilities.SetCurrentThreadCulture("fr-FR");
ConvertUtilities.SetCurrentThreadCulture(1036);
ConvertUtilities.SetCurrentThreadCulture("1036");

Decamelize
Decamelizes the specified text using default decamelization options.

ConvertUtilities.Decamelize("ProductName"); // –> "Product Name"
ConvertUtilities.Decamelize("ProductName", ConvertUtilities.DecamelizeOptions.ForceRestLower); // –> "Product name"

Evaluate

Evaluates the specified expression on a given container object (like Eval in Asp.Net WebForm). In case of an error, the defaultValue parameter will be returned.

ConvertUtilities.Evaluate(DateTime.Now, "TimeOfDay.Hours", typeof(int), defaultValue: 0); // –> 15 (depends of your time<span style="font-family:Wingdings;">J</span> )
ConvertUtilities.Evaluate(DateTime.Now, "TimeOf", typeof(int), defaultValue: 0);  // –> 0
ConvertUtilities.Evaluate(null, "TimeOfDay.Hours", typeof(int), defaultValue:  0); // –> 0 

ConcatenateCollection

Concatenates a collection into a string using a separator character. An expression is ran on each object in the collection using ASP.NET DataBinding syntax style.

List<DateTime> collection = new List<DateTime>
{
   new DateTime(2007, 10, 10),
   new DateTime(2010, 10, 10),
   new DateTime(2014, 10, 10)
};

ConvertUtilities.ConcatenateCollection(collection, "Year", " - "); //- > "2007 - 2010 - 2014"

FormatFileSize

Format file size in bytes to the correct unit.

ConvertUtilities.FormatFileSize(399960003); // –>  381,43 MB
ConvertUtilities.FormatFileSize(399960003, null, "N5", new CultureInfo("en-US")); // –> 381.43158 MB

FromFileExtension

Converts a file extension to the corresponding image format.

ConvertUtilities.FromFileExtension(".jpg"); // –> ImageFormat.Jpeg
ConvertUtilities.FromFileExtension("png"); // –> ImageFormat.Png

IsFlagsEnum

Determines whether the specified enum type has the Flags attribute.

Note: you can use Enum.HasFlag with .Net Framework 4.0 and higher.

ConvertUtilities.IsFlagsEnum(typeof(FileOptions)); // –> true 

GetMaxValue

Gets the maximum value for a given type.

ConvertUtilities.GetMaxValue(typeof(int)); // –> 2147483647 
ConvertUtilities.GetMaxValue(typeof(DateTime));// –> {12/31/9999 23:59:59}

GetUniqueName

Get a name guaranteed not to be in a given a list of names. This method appends numbers to a preferred name.

List<string> names = new List<string>
"Gérald",
"Alexandra",
"Lionel",
"Marc"
};
ConvertUtilities.GetUniqueName(names, "lionel", StringComparison.InvariantCultureIgnoreCase); // –>  lionel2
ConvertUtilities.GetUniqueName(names, "john", StringComparison.InvariantCultureIgnoreCase); // –> john

Nullify

Nullifies the specified string.

ConvertUtilities.Nullify("Windows", trim: true);// –> Windows
ConvertUtilities.Nullify("   ", trim: true);// –> Null
ConvertUtilities.Nullify("   ", trim: false);// –> "  "

RemoveDiacritics

Removes diacritics (accents) from a text.

ConvertUtilities.RemoveDiacritics("éàèçàöâ"); // –> eaecaoa

SplitToList

Splits a text into a collection of typed objects. Returned objects are automatically converted into the proper type if needed.

ConvertUtilities.SplitToList<int>("25,4,15,42", ',');// –> {25, 4, 15, 42}
ConvertUtilities.SplitToList<long>("255,TTT", ',');  // –>{255, 0} Takes the default values of Type 

ToHexa

Converts a byte array to its hexadecimal string representation.

ConvertUtilities.ToHexa(new byte[] {0x43, 0x6F, 0x64, 0x65});// –> "436F6465"

ToHexaDump

Converts a string to its hexadecimal dump representation.

ConvertUtilities.ToHexaDump("CodeFluent Entities");
//Offset    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  0123456789ABCDEF
//--------  -----------------------------------------------  ----------------
//00000000  43 00 6F 00 64 00 65 00 46 00 6C 00 75 00 65 00  C.o.d.e.F.l.u.e.
//00000010  6E 00 74 00 20 00 45 00 6E 00 74 00 69 00 74 00  n.t. .E.n.t.i.t.
//00000020  69 00 65 00 73 00                                i.e.s.
ConvertUtilities.ToHexaDump(new byte[] {0x43, 0x6F, 0x64, 0x65});
//Offset    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  0123456789ABCDEF
//--------  -----------------------------------------------  ----------------
//00000000  43 6F 64 65                                      Code

As you’ve seen in this article, ConvertUtilities can be very useful for .Net developers.

Happy Converting!

The R&D Team

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

Follow

Get every new post delivered to your Inbox.

Join 52 other followers