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:
- In Visual Studio, select DevExpress on the menu, and then Options;
- Select the Editor -> Templates node on the tree;
- Right click the area where the templates are organized by folders;
- Select Import Templates...
- Navigate to the folder where you've unzipped the custom templates and pick the CSharp__EPSCustom.xml file.
- 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).
IDbCommand command = this.NewDbCommand("select * from SomeTable");
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.
IDbCommand command = this.NewDbCommand("select * from SomeTable where field = @id");
this.AddDbCommandParameter(command, "@id", "aa");
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).
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.
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.
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.
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.
private sealed class CustomerCreditMustBeHighBusinessRule : BusinessRule
: 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 (firstname.lastname@example.org) - Comments
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:
- 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.
- 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 (email@example.com) - Comments
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):
- 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.
- 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.
- 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.
- 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:
- 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).
- 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.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.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 (firstname.lastname@example.org) - Comments
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 (email@example.com) - Comments
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 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):
Again, click to enlarge the images.
Posted @ 2:57 PM by Egger, Markus (firstname.lastname@example.org) - Comments
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 (email@example.com) - Comments