Navigation


Milos Solution Platform (External Blog)

The Milos Solution Platform is .NET's premier platform for building business applications. This blog is meant for developers who use or evaluate Milos. This blog is used to share tidbits of information provided by the Milos developers at EPS. Many of the posts put the spotlight on new features. We generally recommend that all Milos users (developers) at least scan this blog to keep up with the Milos news.

Content Area Footer

Saturday, September 08, 2007
Query Simplification

As some of you may know (although not all... which is what we are trying to address), the Milos DataService classes provide a simple way to query multiple records by multiple field names. For instance, if you want to query all customer with a last name of "Pronger" and a first name of "Chris" and active status, then you have been able to simply do this (in a business object):

string[] fieldNames = new string[] { "FirstName", "LastName", "IsActive" };
object[] parameters = new object[] { "Chris", "Pronger", true };
IDbCommand command = this.DataService.BuildQueryCommand("Customers", "*", fieldNames, parameters, DataRowProcessMethod.IndividualCommands);
DataSet customers = this.ExecuteQuery(command);

This is nice, but a lot of people do not know that this functionality exists. Besides, there really is no reason why people would have to know about this somewhat hidden method on the DataService. For this reason, we added a few convenience methods right on the business object that are easier to discover:

string[] fieldNames = new string[] { "FirstName", "LastName", "IsActive" };
object[] parameters = new object[] { "Chris", "Pronger", true };
IDbCommand command = this.GetQueryCommand("Customers", "*", fieldNames, parameters);
DataSet customers = this.ExecuteQuery(command);
 

Or, to make things simpler yet:

string[] fieldNames = new string[] { "FirstName", "LastName", "IsActive" };
object[] parameters = new object[] { "Chris", "Pronger", true };
DataSet customers = this.Query("Customers", "*", fieldNames, parameters);
 

There really is no particular reason for using GetQueryCommand() over Query(), unless you want to first retrieve the command object and then make further modifications on the object (which is hardly ever done). So just use Query().

The values in the field and filter list are all handled as "and" parameters. Also, all fields are used "as is" with no added wild cards. For instance, passing in "Pron" as the last name will not include "Pronger" in the result set. However, it is possible to pass in "Pron%" which will include "Pronger"s, assuming the database understands that wildcard character.

 

Posted @ 1:02 PM by Egger, Markus (markus@code-magazine.com) -
Comments (3)


Wednesday, July 18, 2007
Milos and O/R Mapping: Stored Procedure calls

It's been a while, but let's continue with the series on Milos and O/R Mapping. This time around, discussing Stored Procedure calls.

On the last installment of this series we've seen how to execute queries by running individual SQL statements (dynamic SQL). Executing Stored Procedures is not that much different: the main difference is that instead of using the ExecuteQuery method, we use the ExecuteStoredProcedureQuery method. For example, the following method in a business object would execute a stored procedure named GtPaymentsList:

public DataSet GetPaymentsList()
{
   IDbCommand command = this.NewDbCommand("GetPaymentsList");
   command.CommandType = CommandType.StoredProcedure;
   return this.ExecuteStoredProcedureQuery(command);
}

In case the stored procedure only processes some data and does not return anything to the caller, a method such as the one below will do the job of calling the stored procedure:

public void ProcessPayments()
{
   IDbCommand command = this.NewDbCommand("ProcessPayments");
   command.CommandType = CommandType.StoredProcedure;
   this.ExecuteNonQuery(command);
}

Another aspect of using stored procedures is that we may want all data access in our business objects to go through stored procedures. By default, when we use business objects and entities, Milos uses "individual commands" (dynamic SQL), which means it creates the SELECT, UPDATE, INSERT, and DELETE commands on the fly, depending on what the business object needs. Alternatively, the object can be set so that instead of creating SQL on the fly, Milos can look for Stored Procedures that follow a naming convention (we have code generators that create the necessary stored procedures). In order for that to work, all the developer needs to work is to code-generate the stored procedures, and configure the business object class, by adding the following line to the Configure method:

this.SetDataAccessMethod(EPS.Data.DataRowProcessMethod.StoredProcedures);

Milos can also be set so that the only data access method permitted is through stored procedures (which means that anything going through the data access layer has to be a Stored Procedure call). This can be set by adding the following configuration setting:

<add key="AllowedDataMethod" value="StoredProcedures"/>

That is it for now.  :)



Posted @ 4:45 PM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (3)


Wednesday, June 06, 2007
Recent Grid Enhancements

This upcoming build of Milos has some enhancements to all our grid controls that I know some of you have been waiting for:

  • The grid now supports resorting of bound sortable collections.
  • The grid now automatically (and optionally) remeasures grid row heights when columns are resized. (This is only important in scenarios where grid rows have dynamic heights).
  • The ListBase class (the "mother of all Milos grids") had a problem with owner drawn rows that used variable (non-standard) row-heights. In some special scenario with very few rows shown, scrolling the grid via the mouse wheel caused an exception to be thrown. This has been fixed.
  • As listed in the previous post, there were a number of databinding enhancements.
  • Some people reported problems using the ScrollBottom() method. This has been fixed.
  • The grid now provides better access to the grid row collection. The collection now is enumerable and strongly typed. Both the column and row collections have also been performance optimized.
  • In some rare scenarios, reassigning a data source of the grid caused row selections to go all out of whack. This has been fixed.

In general, quite a few optimizations have been applied to the grid.

Note that these things apply to all Milos grids, including ListBase, the OfficeGrid, the TouchGrid, and even controls such as the list of binary document attachments (among others).



Posted @ 4:17 PM by Egger, Markus (markus@code-magazine.com) -
Comments (7)


Wednesday, June 06, 2007
More Databinding Stuff

Today or tomorrow, we will have a new Milos build. It includes a number of improvements (and some fixes) for WinForms databinding. (Some of which have been discussed before).

Here is a list of a few other things that are included:

  • Both our listbox and combobox classes had some issues binding to data in certain scenarios (basically, our enhancements only handled certain scenarios, but people were left with basic .NET functionality in others). In particular, some scenarios that bound these controls to DataSets or other collections had refresh problems. Enhancements have been made to handle those scenarios properly.
  • There was a problem with the Office Toolbar control that caused people to tab out of the active control before they hit save, otherwise the last edited control was not bound properly. This is fundamentally a .NET issue, so it may still exist in interfaces that do not use these controls (mainly things like third party components), but it has been fixed for Milos controls (Office controls).
  • The Milos date dropdown control (office look and feel) had a few data binding bugs (no way to blame this one on MS or a third party, I am afraid :-)). These are now fixed.
    • This is not related to data binding, but it is worth mentioning that this control now also supports a more lenient data entry. For instance "7/5" is interpreted as July 5th of the current year. (This also works culture specific, so "7.5." in a German app would be interpreted as May 7th of the current year).
  • Standard Milos WinForms radio buttons were not bindable before. They have been enhanced to support data binding.
    • While we were at it, we also added a radio button group container control that makes it quite a bit easier to use and bind radio buttons.
  • All Milos grids have been enhanced quite a bit. Some changes are databinding related (the others I will discuss separately):
    • In the past, editable grids could only bind to data types that matched the controls the column used. So a textbox based edit column could only bind to string properties/fields. This mechanism has now been enhanced to allow automatic parsing for byte, int, decimal, float, double, and datetime fields.
    • Grids now support re-sorting when bound to sortable collections.
    • There also was an issue with bound editable controls that were scrolled horizontally (causing inaccurate placement of the editable areas). This has been fixed.

Not quite databinding, but still related: Milos data edit classes have been cleaned up a bit and optimized. We also added quite a few convenience methods that make it easier to reload data and the like.



Posted @ 4:08 PM by Egger, Markus (markus@code-magazine.com) -
Comments (99)


Wednesday, May 23, 2007
Milos Training: many videos are now available online!

We've created a bunch of videos to help us training new team members on Milos, and we figured these videos should also be helpful for our clients who are using Milos, as well as for those who'd like to check out what kinds of things are part of Milos. Below is a list of the videos currently available, in the respective order they should be watched. We are going to have more videos coming up soon. Stay tuned!

If there are things that you really would like to see explained in videos, please send us an email, and we will definitely consider it. 



Posted @ 1:48 PM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (2)


Wednesday, May 23, 2007
Improvements to the Business Object / Entity generator

One of our main tools in Milos has always been our Business Object / Entity generator, that's available within the EPS Developer Services tool. That feature had some crucial limitations, though, so we've revamped it, including a number of fixes and improvements that we are sure a lot of users are going to appreciate. I'll list some of them here:

  1. Integration with Visual Studio.
    • Previously, the tool worked stand-alone, and the files generated had to be manually included in the project in VS. The current version works as a plugin, running within VS, and that way the files generated get immediately added to the project.
  2. Generation of more than one collection at a time.
    • Previoulsy, one could only create one child collection and one xlink collection at a time. Now any number of collections can be added at a single pass.
  3. Creation of entities that aren't modeled from a SQL Server database.
    • Previously, one could only generate entities based on a table/view in SQL Server. Now we support the creation of an entity from scratch, and underlying data for this entity is stored in XML files. This works great for prototyping modules and creating unit tests without having a need to create tables on the database, which means the developer can concentrate first on the classes to create, and only worry about how to persist that on the backend later. We'll have another post dedicated to this subject soon. It's also worth pointing out that the underlying engine on the generator has gone through a big refactoring to decouple it from SQL Server so to support the entities based on XML data sources. This means that now we can more easily work on adding support to create entities based on other backends such as Oracle, MySql, etc.
  4. Classes can be regenerated.
    • Previously, if the developer needed to add things to a class (say, more properties to a business entity), she'd need to run the tool again, creating the entity as if it were the first time, and then manually move pieces of code from the newly generated files into the existing ones. Yup, painful. The new tool saves the definitions of the objects created, which allows for the tool to recreate the entities without forcing the developer to remember to recreate it as it was done before.
  5. Separation of class in individual files and partial classes.
    • Previously the tool created one file for the business object class, and one file for the business entity class along with its collection and business item classes (collection items). The new tool creates a subfolder in the project, named after the business object (such as CustomerBusinessObject), and put the new files in that folder. Every class goes into its own separate file, and every class is also separated in two files (as a partial class): one for the code-generated content, and one for the custom code developers add to it. This means that the developer can regenerate code for business entities and objects without wiping out the custom code. Yeah, it was about time, right?  ;)

The main point is: the new generator gives us everything we used to have, plus a LOT more, so this is definitely the way to go moving forward. There is only one thing we don't have on the new tool yet: it doesn't auto-update yet. Since it's a VS plug-in, we couldn't just use ClickOnce out of the box. So, if you're creating and working with business objects and entities, send me an email soliciting a copy of the plug-in, and I'll send it to you (of course, you have to be a Milos user to request it. My email is my first name at eps-software.com). I'll put you on my mailing list to receive updates, until we get the auto-update feature into the plug-in.

Also, the installation and usage of this plug-in has been documented in videos. I'll post a blog entry about this shortly. Make sure to check it out!

 



Posted @ 1:31 PM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (6)


Thursday, May 17, 2007
Data binding simplification

Milos controls support native data binding. It has been like that since the beginning of (Milos-) time. So for instance, if you want to bind a textbox to a property on a business entity, you can simply set up the binding by specifying the name of the entity and property you want to bind to, using the ControlSource property of the textbox.

This is pretty straightforward, but there is one somewhat tricky part to this: The member the control binds to is specified from the control's point of view. So for instance, to bind a textbox on a form to a business entity's "LastName" property (assuming the business entity is a member of the same form as is the case with the default Milos data entry forms), the ControlSource has to be set to "this.Parent.MyEntity.LastName". Or, one can also use the VB version: "Me.Parent.MyEntity.LastName". Both these versions are interchangeably and work regardless of the language you use. In fact, the "this/Me" part is completely optional. You could as well set the ControlSource to this: "Parent.MyEntity.LastName".

So far, so good. The tricky part is that if the textbox is inside another container, the hierarchy changes. For instance, if the textbox exists inside a tab page inside a tab control, the ControlSource needs to be set to this: "this.Parent.Parent.Parent.MyEntity.LastName". That is because the textbox exists inside the tab page (Parent), which exists inside a tab control (Parent.Parent), which exists inside the form (Parent.Parent.Parent), which has the entity (Parent.Parent.Parent.MyEntity).

It is perfectly logical, but it is also a common source of frustration, since it is a) easy to get the exact number of parent references wrong, and b) when the control moves into a different container, the path changes. We have now added a simplification to the expressions used by the ControlSource property. The approach described above is still perfectly valid, but the whole "parent" chain is now optional. So the ControlSource can now be set to "MyEntity.LastName", regardless of where the textbox (or any other control with a ControlSource property) lives.

The way this works is that Milos auto-discovers the hierarchy. It starts out with the current control. If it has a "MyEntity" member, then that is used for binding. If not, Milos goes to the parent control and looks for it there. It then continues up the chain until there is no parent anymore (typically at the window level). If no member of the specified name is found, a null reference exception is thrown.

So this is nice, because it simplifies things a lot. There are two downsides though: 1) This discovery is done at runtime and thus introduces runtime overhead. It is pretty fast, but if you have a form with hundreds of controls, you should probably consider specifying the full path (at least that is an optimization option in case you run into form startup performance issues). 2) The expression may be ambiguous. If you want to bind to the MainEntity on the form, but there happens to be another object in the chain that has a member of the same name, you may accidently bind to the wrong object. In those cases, one also has to specify the full path.

Some people say it is a bit odd to just bind to "MyEntity.LastName", because one cannot tell where MyEntity lives. To make things a bit clearer, you can use other pointers, such as "thisform", "class", or "container". They all mean the same exact thing, which is "diddly-squat". In other words: These keywords are ignored completely. But some think it is more readable to set the control source to "thisform.MyEntity.LastName", "Container.MyEntity.LastName", or "class.MyEntity.LastName". So go ahead and use these keywords if you feel they make things clearer. Be aware that they do not actually do anything. "thisform" for instance does not necessarily reference a form. It can also be used in panes for instance. It also does not solve the ambiguity problem, as the auto-discovery mechanism may still pick up "in between" object references from the hierarchical chain. (What do you think about this actually? I'd be interested in feedback on this...).

Anyway: Hopefully, this will simplify the task of specifying the control source expression.

Note: This feature has been implemented and has undergone almost complete testing, so it will most likely show up in the next Milos build...

 

Posted @ 11:48 AM by Egger, Markus (markus@code-magazine.com) -
Comments (8)


Saturday, May 05, 2007
Milos and O/R Mapping: Static and Dynamic Queries


Following the series about Milos ORM capabilities based on this article, up next is the support for Static and Dynamic Queries. Milos does support both.

Essentially, every business object class inherits an ExecuteQuery method. This method takes a Command object. The SQL statement can either be defined during compile-time, with only the parameters filled in at runtime, or any other part of the statement could be built on the fly (like the WHERE clause, or the ORDER BY clause). Below are some ways one could execute queries from within a Milos Business Object.

Simple Query

IDbCommand command = this.NewDbCommand("SELECT * FROM Customers");
DataSet results = this.ExecuteQuery(command);

Simple Query with Parameter

IDbCommand command = 
this.NewDbCommand("SELECT * FROM Customers WHERE PK_Customer = @PK"); this.AddDbCommandParameter(command, "@PK", someGuid); DataSet results = this.ExecuteQuery(command);

A few things to notice so far:

  • We program to the ADO.NET interfaces such as IDbCommand, instead of programming to the concrete implementations, such as SqlCommand, or OracleCommand;
  • We use Factory Methods to create things like the command object or the parameter objects (NewDbCommand and AddDbCommandParameter methods, respectively).
  • The ExecuteQuery method wraps the calls out to the data services layer to deal with connections, data adapters, or anything else that is specific to the data service being used, which can be configured either during runtime or compile time.
  • Since the command text (the SQL statement) is passed as a string, it can be built dynamically depending on some criteria gathered from the user/application. Of course, the database security will prevail, and if a dynamic SQL is created to access some database object that the current user does not have access to, and backend will block it.

Helper methods for simple queries

For some simple queries, one can use some of the helper methods provided by the Milos Business Object. The benefit of using such methods is that we let Milos decided whether to build the SQL statement to be sent to the database, or to call Stored Procedures instead (depending on how the business object is set to process commands). That makes it also easier to swap between using direct SQL statements and stored procedures, or even swap between using different backends, such as SQL Server or MySQL. See some examples below:

Getting all records from a given table

DataSet results = this.QueryAllRecords("Customers");

If the business object is set to process commands using "IndividualCommands", Milos will create the CommandText as SELECT * FROM Customers. On the other hand, if the object is set to use "StoredProcedure", Milos creates a CommandText such as "milos_getCustomersAllRecords". The prefix ("milos_") is configurable, and the other parts of the name of the stored procedure follow a naming convention so that Milos knows what store procedure to look for (we have tools that generate those stored procedures for us!).

The QueryAllRecords method also allows for some customization of what gets retrieved:

DataSet results = 
this.QueryAllRecords("Customers", "PK_Customer, CustomerName", "CustomerName");

Milos would create the following statement for the call above:
SELECT PK_Customer, CustomerName FROM Customers ORDER BY CustomerName

Of course, if the business object is set to use Stored Procedures, then the list of fields and ORDER BY clause on the method call are ignored, and the query in the stored procedure dictates the results.

Retrieving a Single Record

DataSet result = 
this.QuerySingleRecord("Products", "PK_Product, ProductName", "PK_Product", 10);

Milos translates the call above into this:
SELECT PK_Product, ProductName FROM Products WHERE PK_Product = 10

Retrieving Multiple Records by a given Key

DataSet results = 
this.QueryMultipleRecordsByKey("Customers", "CustomerName", "State", "TX");

The call above is translated into this:
SELECT CustomerName FROM Customers WHERE State = "TX"

This helper method is also great to get all the children rows for a specific parent, like this:

DataSet results = 
this.QueryMultipleRecordsByKey("Orders", "OrderDate", "FK_Customer", someGuid);

that translates into SELECT OrderDate FROM Orders WHERE FK_Customer = someGuid

On the next post, we'll talk a little more about Stored Procedures. Stay tuned!



Posted @ 11:37 AM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (7)


Wednesday, April 18, 2007
EPS CodeRush Custom Templates

I have personally be using CodeRush for about 2 years now, and I've been creating custom templates for some things that I do all the time, both for .NET in general and for Milos things. Since we're now getting other EPS developers to use CodeRush too, and I know there are many of our clients also using CodeRush and Milos, I'll be sharing here my custom templates. This is important for both beginner Milos users learning how to use the framework, as well as for advanced users who already know what to do and want to do it quickly.

You can download our custom templates here. There is a 6-minute training video on how to share templates among developers here. A brief how to goes here:

  1. In Visual Studio, select DevExpress on the menu, and then Options;
  2. Select the Editor -> Templates node on the tree;
  3. Right click the area where the templates are organized by folders;
  4. Select Import Templates...
  5. Navigate to the folder where you've unzipped the custom templates and pick the CSharp__EPSCustom.xml file.
  6. Click OK or Apply, and you're done!

Here's a list of some the templates we currently have, and what they expand to (I will not list all of them, since some I may still be tweaking or may end up droppng it from the list). Notice that everything in italic on the expansion indicates the pieces that the developer has to key in (the template will usually create stubs for it if possible):

Template:  eq  (as in Execute Query)

Usage: from with a method on a business object class, use this template when you need to execute a SQL statement against the database. If you already have a SQL statement into the clipboard, the template will paste it on the right place (as a parameter to the NewDbCommand method).

Expansion:

IDbCommand command = this.NewDbCommand("select * from SomeTable");
return this.ExecuteQuery(command);


Template
:
eqp (as in Execute Query with Parameter)

Usage: same as "eq" template, except that this one will add the necessary call to add a parameter to the query.

Expansion:

IDbCommand command = this.NewDbCommand("select * from SomeTable where field = @id");
this.AddDbCommandParameter(command, "@id", "aa");
return this.ExecuteQuery(command);

Template: esp (as in Execute Stored Procedure), and espp (as in Execute Stored Procedure with Parameter)

Usage: same as "eq" and "eqp", but it expands to a call a Stored Procedure instead.


Template:
ndbc (as in New DB Command)

Usage: within a method on a business object class, expands to the line necessary to a get new DB command using Milos (pastes content from the clipboard, such as s SQL statement into the code).

Expansion:

IDbCommand command = this.NewDbCommand("Select * from table");


Template:
acp (as in Add Command Parameter)

Usage:  within a method on a business object class, expands to the line necessary to add a parameter to a command object.

Expansion:

this.AddDbCommandParameter(command, "@param", "value");


Template:
ubo (as in Using Business Object)

Usage: within a code block, expands to a using block, and all the developer has to do is to type the main name of the business object (such as Customer); the template will take care of properly naming the type and variable with the right casing.

Expansion:

using (CustomerBusinessObject customerBO = CustomerBusinessObject.NewInstance())
{
                    
}


Template:
ube (as in Using Business Entity) and unbe (as in Using New Business Entity)

Usage: same as "ubo", except that it will create the using block wrapping a business entity. "ube" expands so that it calls LoadEntity (to load an existing row from the database), whereas "unbe" expands so that it calls NewEntity (to create a brand new row on the database).


Template:
nbo (as in New Business Objects), nbe (as in New Business Entity), and lbe (as in Load Business Entity).

Usage: all these templates will declare a variable, name it, and instantiate it, depending on what main name for the class the developer types. NOTE: these templates should only be used in case the objects are not to be disposed by the method creating them. Favor using the "ubo", "ube", "unbe" templates instead, since the using block disposes the object automatically.

Expansion (respectively):

CustomerBusinessObject customerBO = CustomerBusinessObject.NewInstance();
CustomerBusinessEntity customerBE = CustomerBusinessEntity.NewEntity();
CustomerBusinessEntity customerBE = CustomerBusinessEntity.LoadEntity(pk);

Template: cbr (as in Class Business Rule)

Usage: expands to a class definition that inherits from the Milos BusinessRule class.

Expansion:

private sealed class CustomerCreditMustBeHighBusinessRule : BusinessRule
{
    public CustomerCreditMustBeHighBusinessRule()
           : base("Customers", RuleViolationType.Violation)
    {
    }

    public override void VerifyRow(DataRow currentRow, int rowIndex)
    {
        this.LogBusinessRuleViolation(currentRow, rowIndex, "Balance", "Credit must be high.");
    }
}

C#, VB, and VS Code Snippets

Right now, our custom templates only support C#; we will work on support for VB as well. We are also considering creating templates using Visual Studio's "Code Snippets" (for those who aren't using CodeRush), but we don't have a timeframe for that yet. 

More custom templates?

We are certainly going to create more custom templates as time goes by, and as we do, we'll make it available, and post the updates to this blog so that everybody can be aware of it. If you think of any template that would be really helpful to have, shoot me an email, and I'll see if we can implement it.   

 



Posted @ 4:32 PM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (8)


Wednesday, April 18, 2007
Milos and O/R Mapping: Object Inheritance

As mentioned in the "Top 10 Must Have Features in O/R Mapping Tools" article, inheritance is one of the core concepts in object-oriented programming, and relational databases don't support such concept. Milos Business Objects do support means for that, though. This can happen in two ways:

  1. A business object (say ContactBusinessObject), and its MainEntity (main table) is set to "Contacts". A business entity is created to expose the main information such as the contact's name, address, phone numbers, etc. Subclasses of the ContactBusinessObject/Entity are created, and additional behavior is added to it. Both classes use the same table.

  2. Continuing with the "Contact" business object/entity example. Like on the first example, we make the Contacts table the MainEntity of the business object. Then we create a subclass, say "EmployeeBusinessObject" (and entity). An "employee" is-a "contact" (an employee has a name, addresses, phone numbers, etc.), but also has additional information (payroll info, job title, etc.). In the database, there is an Employees table, with a one-to-one relationship to the Contacts table. The EmployeeBusinessObject will have data from the Contacts table loaded (since that happens at the ContactBusinessObject), and it also loads the related data from the Employees table. The EmployeeBusinessEntity exposes properties that map to the columns off the Contacts table, as well as the ones off the Employees table.

In fact, Milos has a NameComponents module, which has a set of classes to be used for "names" (or contacts) manipulation (that includes business object, entity, and UI controls). That way, we don't have to recreate that functionality over and over again. We then subclass those business object/entity classes, to extend it into special classes such as Employee, Customer, and anything else that is-a specialized version of a contact in the application.

I'd like to mention that I'm keeping the posts on this series short, since my main focus at this point is to mention whether or not (and a little bit of how) Milos supports those "top 10 must have features"; when we're done with the series, I'll spend some more time into actually posting more details on each of those features. Stay tuned!



Posted @ 9:37 AM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (18)


Friday, April 13, 2007
Milos and O/R Mapping: Relationships and life cycle management

Following the series based on this article, this next installment covers how Business Objects module in Milos deals with Relationships and Life Cycle Management. So here we go (again, basing the contents off of the aforementioned article):

  1. One-to-One relationship: as I said in another post, we create business entity objects in Milos, and this objects usually have properties that map to column from a table, but, it can also have a property that exposes another entity that models another table. For instance, a database may have a Customers table, and a CustomerSensitiveData table (these tables have a one-to-one relationship). We could then create two business entities, one for each table, and each entity would have a property exposing the other one (i.e., the CustomerBusinessEntity class would have a property of type CustomerSensitiveDataBusinessEntity, and vice-versa, if needed). That way, people using a Customer object, could get to the sensitive data (if authorized to do so) by doing some like Customer.SensitiveData.SomeSecureInfo. By having both entities sharing the save DataContext, both loading and saving operations would be synchronized between the entities. Alternatively, instead of creating a separate entity for the sensitive data, we could just add properties to the Customer business entity that map to the columns in the sensitive data table. Therefore, the syntax from the previous example would be Customer.SomeSecureInfo. Even though the object looks like a single unit, internally it really manages a one-to-one relationship between two tables.

  2. Many-to-One relationship: I can't really think of a scenario where we've implemented this kind of relationship. For sure, we do a lot of "one-to-many" ones (covered next), but I really can't think of a many-to-one scenario. Well, let me know if you can think of one, and I'll check out how to implement it using Milos.

  3. One-to-Many: this scenario is very simple in Milos; we create, for instance, an OrderBusinessEntity, which maps to an "Orders" table, and then add an Items collection to the entity, mapping to the "OrderLineItems" table, in a one-to-many relationship. All the loading and saving is handled by the business entity/object. The developer instantiates an Order entity, add items to it through the collection, and when calling Save on the entity, both the data for the Orders and OrderLineItems tables get saved. Likewise, when the developer loads the entity based on an Order PK, both the order and its related line items are retrieved from the database. For the records, we call this kind of collection a "Child Collection" in Milos.

  4. Many-to-Many relationship: this scenario is also handled nicely in Milos. The bridge table glues the two main tables together. That table is also known as a joint table. In Milos, we call them cross link table, or just XLink for short. So let's think of a Product / Vendor relationship, where a Product can be offered by many Vendors, and one Vendor can offer many Products. One way of looking at this is from the Product's perspective (say we create a product, and associate a vendo with it). We'd define a ProductBusinessEntity, where the master table (or parent table, or MasterEntity, as we call it) is "Products", the XLink table is "ProductVendorsXLink", and the "Vendors" table we call the "target table" (since it is "the other end of the relationship"). Again, all the loading and saving is handled by the entity and business object. For the records, this kind of collection is called "XLink Collection" in Milos. Notice that the bridge (or XLink) table, can come in two flavors, listed below. Notice that Milos works with both case seamlessly:

    1. Bridge table with only primary key: this means that all the table has is the primary keys from both ends of the relationship (in the example mentioned, that'd be the PKs from both the Products and Vendors table, since that's what links the two together).

    2. Bridge table with additional columns: in this case, the bridge table would have more information about the relationship between the two ends. For instance, a "banana" product sold by "Mr. Banana Man" vendor would have one price, whereas the same product sold by a "King of Bananas" vendor could have a different price. The Price column would map to a Price property on the XLink collection, so from the developer's point of view, that value could be retrieved like so: SomeProduct.Vendors[0].Price. Notice that, if needed, we could bring some more info about the Vendor, such as the address, which could be accessed like SomeProduct.Vendors[0].Address (notice that from the object's perspective, it's very convenient to use, and internally, we still have everything persisted in a relational fashion).

For all these scenarios, we have code generator (that runs as a plug-in for Visual Studio) that facilitates a lot the creation of the objects, already configured to be used right away. In a couple of days I'll be posting about a new version of our code generator that's coming out soon.



Posted @ 9:33 AM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (5)


Monday, April 09, 2007
Milos and O/R Mapping: Transactional Operations


Following the series on Milos O/R Mapping features, this post tackles transactional operations. Essentially, our business objects automatically wraps up saving operations into transactions. Nothing special has to be done by the developer to enable this.

In more specific scenarios, the developer may want to start a new transaction and control it manually. The BusinessObject class provides methods such as BeginTransaction, EndTransaction (commit), and AbortTransaction (rollback). Those are wrappers around the connection object to deal with transactions.

There are also other scenarios where the developer may need to save many entities wrapped up in a single transaction. For that to happen, an "atomic save" has to be used. In other scenarios, a business object may need to "see" some data that has not yet been comitted from a transaction. For instance, a BusinessRule object (which is associated with a business object), may need to validate some data based on some other data not yet commited by a transaction created by another business object; in such case, both business objects must share the same data context so that one can "see" the uncommitted data of the other. Check out this other post on "Atomic Saves and Transactions" for a quick example on this. 

We currently don't have a strong support for COM+/MTS transactions.



Posted @ 9:23 AM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (6)


Thursday, April 05, 2007
Application Form Face-Lift

The most recent version of Milos (deployed just a few days ago) has updates the the look and feel of some of our "Office controls". An easy way to see the updates is to look at a new version of the OutlookApplicationForm (which replaces the older EPSOutlookApplicationForm... the two are almost compatible and one can move from one to the other with very little effort).

Here is a version shown on Windows Vista:

Click to zoom...

(Click on the image to get a zoomed view...)

Some things to note here: The form now picks up more accurately on the current Windows color scheme (gray/black in this example). It also renders in more of a glassy appearance. It isn't quite like Vista glass (for that, you need our WPF components), but it is pretty cool looking. Note the details, such as the headers of the panes ("One", and "Content...") are rendering in a glassy look. (The old gradient look is still supported). The same is true for the category bars ("One", "Two", "Three") which are now also sporting a glassy look. And so are the column headings in the grid.

What you can't see in this screenshot is that we also improved the rendering algorithm for all this, which drastically reduces screen flicker.

Here's what this looks like on Windows XP (blue, green, and silver default themes):

Click to zoom...  Click to zoom...  Click to zoom...

Again, click to enlarge the images.



Posted @ 2:57 PM by Egger, Markus (markus@code-magazine.com) -
Comments (13)


Monday, April 02, 2007
Milos and O/R Mapping: The use of your existing domain objects

Keeping with the series on O/R Mapping capabilities in Milos, basing it off on the features listed in this article, the next in line is "Feature 2: Use your existing domain objects".

A core part of Milos is its Business Objects and Business Entities. The Business Entity is the "domain" object; this is the object that represents one row of data from a table on the database. This object has properties that expose some or all the columns from a table, and it also has collections to represent the child data of the given entity (modeling one-to-many and many-to-many relationships). For instance, a CustomerBusinessEntity is an object that models one customer from the database; it has properties such as Name, DataOfBirth, Ssn, Addresses (this one being a collection containing all of the customer's addresses), etc.

The entity is very handy to gather data from the user or displaying the data (this is done by binding the entity to UI controls). Of course, the entity can also be used entirely programmatically, feeding its data through code (as opposed to getting it from the user).

The entity's counterpart is the Business Object. This object is responsible for offering some services to the entity. This includes retrieving data from the persistence layer (database), validating data against business rules before pushing it back to the persistence layer, and executing other sorts of business logic (like processing some data according to some business logic). This object can also be seen as a "factory" object, producing data for business entities to consume. Following our previous example, a CustomerBusinessEntity's counterpart would be a CustomerBusinessObject, which knows, for instance, how to load a customer from the database by a given Id, retrieving the customer's main data along with child data.

A business object can stand on its own, whereas a business entity depends on a business object to do its job.

We have a tool that's part of Milos, called EPS Developer Services, which automates the creation of business objects and entities; the developer creates those objects based on a "main" domain from an existing database (such as a Customers table along with its child tables).

Currently, the tool always creates the pair (the business object and the business entity). The developer can, however, create the entities manually, even though it's just much easier to have the tool generate the code for it. If the scenario is such so that there is no table on the database to feed that object (which is the case when the developer is writing code test-first, designing the objects without worrying about how they will end up persisted in a database), the tool allows the developer to create an entity from scratch visually, by adding properties, collections, etc. This feature has been available in Alpha version for a few months now, and there's an update to it coming out soon.

On this new version of the Developer Services tool, we're also allowing the developer to regenerate code without wiping out custom things created since the original generation. I'll save more information on this for another post when we ship this new version (in the next few days).



Posted @ 10:01 AM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (9)


Thursday, March 29, 2007
Milos Business Objects and "Flexible Object Mapping"



The Milos Business Objects and Business Entities provide features that fall well into the "Flexible Object Mapping" category (see "Feature 1: Flexible object mapping" in this article).

  1. Tables and views mapping: the business objects support both tables and views as the main source behind it, by just specifying the name of the table or view in the MasterEntity property of the BusinessObject.

  2. Multi-table mapping: the MasterEntity is usually the main table or view behind the business object, and related tables (either child tables or lookup tables) can be retrieved by override the business object's LoadSecondaryTables method.

  3. Naming convention: the business objects and entities definitely provide that. For instance, a CustomerBusinessObject's MainEntity could be a "v_Customers" view on the database. The view columns are represented in a business entity by a friendly property; for instance, a "cust_fname" column would be exposed as a "FirstName" property on the business entity.

  4. Attibute mapping:

    1. Primary key: the primary key column is specified by setting the PrimaryKeyField property on the business object. The column is exposed through the business entity by means of the PK property (every entity inherits this property, which maps to whatever column has been specified by the PrimaryKeyField property). Currently only single-column keys are allowed.

    2. Auto generated columns: if the business object is set to use "auto-increment integer" primary keys, it handles retrieving the key created by the database. For other types of values generated by the database, they can be retrieved by simply reloading a business entity, which will bring down fresh data for the object.

    3. Read-only columns: read-only columns are implemented as properties on the business entity; such property only has a get method. If the value for the column is generated by the database, it'll be available for the entity as soon as it gets created.

    4. Required columns: required columns are specified by adding the EmptyFieldBusinessRule to the business object's BusinessRules collection.

    5. Validation: validation for the data handled by the business object is done by creating subclasses of the BusinessRule class, implementing the validation code, and then adding an instance of the class to the business object's BusinessRules collection.

    6. Formula Fields: a business entity can have any kind of property. A "formula field" could be a property on the entity, that only has a get method, and within the get method, it can perform anything that's needed (like combining values from other properties and/or values read from the object's internal state - by means of calling the entity's GetFieldValue method).

    7. Data type mapping: type mapping is implemented as a typical .NET conversion. If a value is stored in the database as an integer, but there's a need to expose it through the entity as a string, a property of type string is added to the business entity, and we perform the conversion when reading the data off the object's internal state (i.e., this.GetFieldValue("SomeField").ToString()), or when setting its value. Another example is when an image is stored as an "image" type on the database, but then exposed as a Bitmap object through the entity. This is all possible.

If you want more info about any of those items, email me, and I'll post another entry here with more details.



Posted @ 9:30 AM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (82)


Tuesday, March 27, 2007
Milos and Object-Relational mapping (ORM) tools


Every once in a while we get asked whether Milos has ORM tools, or how does Milos fit with ORM. Recently I've run accross this article: Top 10 Must Have Features in O/R Mapping Tools. It's a good quick read to learn a little about ORM tools. As I was reading the article, I was mentally mapping the features mentioned in the article to how they're are (or are not) implemented in Milos, and figured some of those may not be as clear to Milos users out there.

Over the next days I'll be posting to this blog many entries where I'll take each one of those features and explain how they exist (or not) in Milos. Make sure you read the article first, and then keep tuned for the upcoming posts.  ;)



Posted @ 10:33 AM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (86)


Thursday, March 22, 2007
Removing Collection Items by Primary Key

Boy, we've had tons of small improvements lately, quite a few of which are worth blogging about. Here is another one: It is now easily possible to remove items from a business entitie's sub item collection by its primary key. Here is an example:

Invoice.LineItems.RemoveByKey(guid);

This works with all key types (Guids, ints, strings).



Posted @ 4:34 PM by Egger, Markus (markus@code-magazine.com) -
Comments (114)


Wednesday, March 21, 2007
Checking Certain Types of Business Rules Only

The Verify() method on business objects and business entities now has a new overload which allows to check a certain type of business rule only:

entity.Verify(typeof(Rules.GreaterThanBusinessRule));

Note that this checks all rules of the specified type, or rules derived from that type.



Posted @ 8:32 PM by Egger, Markus (markus@code-magazine.com) -
Comments (4)


Wednesday, March 21, 2007
Minor Empty Field Business Rule Enhancement

The empty field (required field) business rule has been enhanced to also consider Guid.Empty as a missing field. (Empty guids are really all 0's, so they were previously not considered empty in this rule).

Also, a minor change has been made to make sure null-values and System.DBNull are detected as empty in all cases.



Posted @ 8:29 PM by Egger, Markus (markus@code-magazine.com) -
Comments (115)


Wednesday, March 21, 2007
StringHelper.ToFile() and Encoding

The latest version of the StringHelper class now features and overload of the ToFile() method that supports the definition of encoding settings.

EPS.Utilities.StringHelper.ToFile(actual, "Test.txt", Encoding.Unicode);

The following example writes a string in the default Windows codepage:

EPS.Utilities.StringHelper.ToFile(actual, "Test.txt", Encoding.GetEncoding(1252));

If your international special characters do not come out write, then it is probably an encoding issue, which you can solve by specifying the encoding.



Posted @ 7:14 PM by Egger, Markus (markus@code-magazine.com) -
Comments (4)


More Posts: Newer Posts - Older Posts

 

 

 

 

 

 

 

Syndication RSS 2.0 RSS 2.0

All My Blogs:
My personal blogs:
Dev and Publishing Dev and Publishing
Travel and Internat. Living Travel and Internat. Living
Other blogs I contribute to:
Milos Blog (US) Milos Blog (US)
VFPConv. Dev Blog (US) VFPConv. Dev Blog (US)
VFPConv. Dev Blog (DE) VFPConv. Dev Blog (DE)

 

Blog Archives
All Blog Posts

2010
    November (1)
2009
    July (2)
    February (2)
    January (1)
2008
    December (1)
    October (3)
    June (1)
    April (3)
    February (1)
    January (1)
2007
    December (1)
    October (2)
    September (2)
    July (1)
    June (2)
    May (4)
    April (6)
    March (8)
    February (3)
    January (2)
2006
    December (2)
    November (2)

 

 

 

This Blog is powered by MilosTM Collaboration Components.