Skip to content

Commit

Permalink
Import docs from the wiki
Browse files Browse the repository at this point in the history
  • Loading branch information
jonorossi committed Jun 4, 2015
1 parent 4173c22 commit 6ad46de
Show file tree
Hide file tree
Showing 35 changed files with 4,571 additions and 0 deletions.
60 changes: 60 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Castle ActiveRecord Documentation

<img align="right" src="images/castle-logo.png">

The **Castle ActiveRecord** project is an implementation of the [ActiveRecord pattern](http://en.wikipedia.org/wiki/Active_record) for .NET. The ActiveRecord pattern consists on instance properties representing a record in the database, instance methods acting on that specific record and static methods acting on all records.

**Castle ActiveRecord** is built on top of [NHibernate](http://www.nhibernate.org/), but its attribute-based mapping frees the developer of writing XML for database-to-object mapping, which is needed when using NHibernate directly.

:warning: **Warning:** Although ActiveRecord makes using NHibernate easy it does not hide all details of NHibernate behaviour. You **need** to understand NHibernate flushing behaviour and how to work with text/ntext columns.

## Reference Manual

* [Understanding Scopes](understanding-scopes.md) - Explains the SessionScope and TransactionScope classes
* [Validators](validators.md)
* [XML Configuration Reference](xml-configuration-reference.md)

## User's Guide

* [Getting Started](getting-started.md) - A tutorial for "how", after the introduction explains "what"
* [Configuration and Initialization](configuration-and-initialization.md) - Explains the configuration options and schema, and provides some illustrative examples as well
* [Creating an ActiveRecord class](creating-an-activerecord-class.md)
* [The Persistency Lifecycle](persistency-lifecycle.md)
* [Primary Key Mapping](primary-key-mapping.md)
* [Simple Column Mapping](simple-column-mapping.md)
* [Relations Mapping](relations-mapping.md)
* [BelongsTo](relations-mapping.md#belongsto)
* [HasMany](relations-mapping.md#hasmany)
* [HasAndBelongsToMany](relations-mapping.md#hasandbelongstomany)
* [OneToOne](relations-mapping.md#onetoone)
* [Any and HasManyToAny](relations-mapping.md#any-and-hasmanytoany)
* [Schema Generation](schema-generation.md)
* [Unit Testing](unit-testing.md)
* [Type Hierarchy](type-hierarchy.md) - Discuss approaches to achieve inheritance within your object model and map it correctly to the underlying database
* [Nested Data (NHibernate Components)](nested-data.md)
* [Using HQL (Hibernate Query Language)](using-hql.md) - Illustrates the usage of HQL
* [Native SQL Queries](native-sql-queries.md)
* [Using Scopes](using-scopes.md)
* [Enabling Lazy Load](enabling-lazy-load.md)
* [Validation Support](validation-support.md) - Presents the ActiveRecordValidationBase that is able to validate properties with predefined validators
* [Best Practices](best-practices.md) - Some recommendations
* [Web Applications](web-applications.md)
* [Troubleshooting](troubleshooting.md) - Something went wrong? Check what problems we had and how we work around them
* [Frequently Asked Questions](faq.md)
* [External Articles on ActiveRecord](external-articles.md)

## Advanced Usage

* [Using the ActiveRecordMediator (avoiding a base class)](using-the-activerecordmediator.md)
* [Using Version and Timestamp](using-version-and-timestamp.md)
* [Using Imports](using-imports.md)
* [Hooks and Lifecycle](hooks-and-lifecycle.md)
* [Framework Events](framework-events.md)
* [Accessing more than one database](accessing-more-than-one-database.md)
* [Tuning (Performance Improvements)](tuning.md)
* [ByteCode Generator and Scopeless Lazy Loading](bytecode-generator.md)

## Integrations

* [MonoRail ActiveRecord Integration](https://github.com/castleproject/MonoRail/blob/master/MR2/docs/activerecord-integration.md)
* [MonoRail ActiveRecord Scaffolding](https://github.com/castleproject/MonoRail/blob/master/MR2/docs/getting-started-with-activerecord-integration.md)
27 changes: 27 additions & 0 deletions docs/accessing-more-than-one-database.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Accessing more than one database

You can use more than one database with ActiveRecord. In order to do so you must create base classes that define, based on the hierarchy, which database is being used. Those are called *Root types*. If you use just one database, the *root type* is `ActiveRecordBase`.

## Adding a different database

Let's analyze the steps involved in getting ActiveRecord to work with more than one database.

### First: Create your root type

You must create an abstract class. It is recommended that this class extends ActiveRecordBase, because all *ActiveRecord types* bound to the second database must use it as the base class. This class can be empty.

However, it is not necessary to extend ActiveRecordBase. When ActiveRecord is used without base types (using ActiveRecordMediator), there is no gain from extending ActiveRecordBase, and inheriting from it can be safely omitted.

```csharp
using Castle.ActiveRecord

public abstract class LogisticDatabase : ActiveRecordBase
{
}
```

The class must not create a table by its own. It cannot be used as direct base class for single table or class table inheritance as described under [Implementing Type hierarchies](type-hierarchy.md).

### Second: configure the second database

On the existing configuration, you must use add another config set bound to the abstract class you have just created. For more information on it, see [XML Configuration Reference](xml-configuration-reference.md).
31 changes: 31 additions & 0 deletions docs/best-practices.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Best Practices

After eating our own dog food for a while, we think we might have some valuable tips for newcomers.

## Create test cases for your domain model

Having test cases for your domain model allow you to easily identify what change broke some functionality. This is a general rule for test cases but some people tend to neglect test cases for things that involve databases.

We think that testing each layer individually is important, including the data access layer. Just make sure there is a separated databases to be used exclusively by the test cases.

As the application grows big, you might end up with a complex object model with lots of interconnections. So testing become a complex issue, for example, imagine that you want to test an Order class, but to test it you must create a Product, and a Supplier and an Consumer.

We recommend using [ObjectMother pattern](http://martinfowler.com/bliki/ObjectMother.html) for such cases.

## Test interactions and relations

The interactions among objects are especially important. When they are meaningful, create special methods for them that assert some conditions.

For example, suppose you have a `Pool` and `Vote` classes. The `Pool` might expose a `RegisterVote` method. Have your test asserting the correct behavior for it.

## Use relations wisely

There are a number of things ofter overlooked when relations are defined. The Inverse property for example, defines which side of the relation manages the collection. The types used (`List`, `List`) have an implied semantic which often is not considered.

The best source of information about relations is (and will ever be) the [NHibernate documentation](http://nhforge.org/doc/nh/en/index.html).

## Define a Cascade behavior for your relations

The cascade defines how NHibernate should handle children/parent associations when something is changed or deleted. Castle ActiveRecords always defaults to `None` so it is up to you to specify the behavior you want.

One more time the best source of information about cascades is the [NHibernate documentation](http://nhforge.org/doc/nh/en/index.html).
116 changes: 116 additions & 0 deletions docs/bytecode-generator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# ByteCode Generator and Scopeless Lazy Loading

ActiveRecord provides a custom ByteCode generator, based off of the Castle ByteCode packaged with NHibernate. The ActiveRecord ByteCode provides additional session management functionality not found in the standard implementation.

A ByteCode provides the object proxies used when lazy loading entities from the database. Please see [enabling lazy load](enabling-lazy-load.md) for additional information on how to use ActiveRecords lazy functionality.

ActiveRecord can lazy load three types of objects:

* ActiveRecord objects
* Properties
* Relationships

The ActiveRecord ByteCode will provide session management for lazy ActiveRecord objects. As a result, you do not need to provide a session scope when accessing these objects.

:warning: **Warning:** Session management of lazy properties and relationships is not currently supported. These must still be accessed from within the original SessionScope.

For example, if you have the following classes defined:

```csharp
using Castle.ActiveRecord;

[ActiveRecord(Lazy=true)]
public class Customer : ActiveRecordBase
{
private int id;
private string name;

[PrimaryKey]
public virtual int Id
{
get { return id; }
set { id = value; }
}

[Property]
public virtual string Name
{
get { return name; }
set { name = value; }
}
}

[ActiveRecord]
public class Order : ActiveRecordBase
{
private int id;
private Customer owner

[PrimaryKey]
public virtual int Id
{
get { return id; }
set { id = value; }
}

[BelongsTo(Lazy = FetchWhen.OnInvoke)]
public Customer Owner
{
get { return owner; }
set { owner = value; }
}
}
```

Using the ActiveRecord ByteCode, you may access a Customer like this:

```csharp
Customer customer = Customer.Find(1);

Console.WriteLine(customer.Name); // loads data
```

The standard Castle ByteCode would throw a LazyInitializationException when customer.Name was accessed. In other words, you don't need a underlying opened SessionScope when you replace the standard bytecode provider with the AR one.

Lazy objects can also be accessed through a BelongsTo relationship.

```csharp
Order order = Order.Find(1);

Console.WriteLine(order.Owner.Name);
```

The ActiveRecord ByteCode will also allow you to move lazy objects between sessions without error.

```csharp
Order order;
using(new SessionScope())
{
order = Order.Find(1);
}

//...snip...
using(new SessionScope())
{
Console.WriteLine(order.Owner.Name);
}
```

## Configuration

To use the ActiveRecord ByteCode you must reference it when configuring ActiveRecord. Set the proxyfactory.factory_class attribute to "**Castle.ActiveRecord.ByteCode.ProxyFactoryFactory, Castle.ActiveRecord**".

For instance, you may have the following in your XML configuration file:

```xml
<activerecord>
<config>
<add key="connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
<add key="dialect" value="NHibernate.Dialect.MSSql2005Dialect" />
<add key="connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
<add key="connection.connection_string" value="Server=(local)\sqlexpress;initial catalog=test;Integrated Security=SSPI" />
<add key="proxyfactory.factory_class" value="Castle.ActiveRecord.ByteCode.ProxyFactoryFactory, Castle.ActiveRecord" />
</config>
</activerecord>
```
153 changes: 153 additions & 0 deletions docs/configuration-and-initialization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Configuration and Initialization

Before using an ActiveRecord class in runtime you must properly initialize the framework. This must happen only once for the entire application lifetime.

In order to initialize the framework, you must supply some obligatory information.

* What kind of database you are using
* How to connect to it

Optionally you can turn debug on, turn on caching and make fine tune adjustments. The sections below explain how to start the framework and give it all information it needs to initialize itself properly.

## Initializing

Before using ActiveRecord your application must invoke the method `Initialize` on `ActiveRecordStarter`. This method has a few overloads. Ultimately it needs an implementation of `IConfigurationSource` and a set of ActiveRecord types to inspect. It basically configures NHibernate, inspects the types for semantic errors and constructs the mapping for each of them.

In this section we will postpone the construction or obtention of an `IConfigurationSource` and focus the attention on the overloads.

### Initialize(IConfigurationSource source, params Type[] types)

This overload allow you to specify an IConfigurationSource and an array of ActiveRecord types. For example:

```csharp
using Castle.ActiveRecord;

IConfigurationSource config = ... ;

ActiveRecordStarter.Initialize(config, typeof(Blog), typeof(Post));
```

:information_source: When you use this overload you must remember that once you add one or more ActiveRecord types you must include the types on the call, otherwise the new types will not work.

### Initialize(Assembly assembly, IConfigurationSource source)

This overload allow you to specify an `IConfigurationSource` and an `Assembly` instance. ActiveRecord then iterates over all types on the Assembly and initializes the types it identifies as ActiveRecord types. The implementation checks whether the type uses the `ActiveRecordAttribute`.

Using this overload saves you from updating the call everytime a new type is included to your domain model.

Example:

```csharp
using Castle.ActiveRecord;

IConfigurationSource config = ... ;

Assembly asm = Assembly.Load("Company.Project.Models")

ActiveRecordStarter.Initialize(asm, config);
```

:warning: **Warning:** Try to create an `Assembly` exclusively for ActiveRecord types if you can. This overload will inspect all public types. If there are thousands of types, this can take a considerable amount of time.

### Initialize(Assembly[] assemblies, IConfigurationSource source)

Just like the overload above, this overload allow you to specify an `IConfigurationSource` and an array of `Assembly` instances. ActiveRecord then iterates over all types on the `Assembly` array and initializes the types it identifies as ActiveRecord types. The implementation checks whether the type uses the ActiveRecordAttribute.

This overload is useful when you have reusable ActiveRecord classes and a project uses a combination of reusable classes and their own types.

Example:

```csharp
using Castle.ActiveRecord;

IConfigurationSource config = ... ;

Assembly asm1 = Assembly.Load("Company.Common.Models")
Assembly asm2 = Assembly.Load("Company.Project.Models")

ActiveRecordStarter.Initialize(new Assembly[] { asm1, asm2 }, config);
```

### Initialize()

This overload uses an assumption to initialize the framework. It assumes that:

* The configuration can be obtained from the configuration associated with the AppDomain (more on that on the next section).
* All ActiveRecord types can be found on the executing assembly.

As much as this is the simpler overload, it is also the one which imposes more restrictions. As a general rule, do not use it.

```csharp
using Castle.ActiveRecord;

ActiveRecordStarter.Initialize();
```

## Configuring

Configuring Castle ActiveRecord is necessary as it will never be able to guess the database you are using or the connection string. When you configure it, you end up configuring the NHibernate instance ActiveRecord uses, and some other configuration is specific to ActiveRecord.

Basically you need to tell:

* The driver
* The dialect
* The connection provider
* The connection string

These entries are not optional and must be informed. Optionally you can configure caching, schema name, query substitutions. You can find more information about those on NHibernate documentation.

Castle ActiveRecord abstracts the configuration from its source using the interface IConfigurationSource. You can construct an implementation yourself if you want to, or you can use one of the three implementations provided, which are listed below.

### InPlaceConfigurationSource

The `InPlaceConfigurationSource` allows you to hardcode the information (or at least part of it) required to configure.

```csharp
using System.Collections;
using Castle.ActiveRecord.Framework.Config;

IDictionary<string, string> properties = new Dictionary<string, string>();

properties.Add("connection.driver_class", "NHibernate.Driver.SqlClientDriver");
properties.Add("dialect", "NHibernate.Dialect.MsSql2000Dialect");
properties.Add("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
properties.Add("connection.connection_string", "Data Source=.;Initial Catalog=test;Integrated Security=SSPI");

InPlaceConfigurationSource source = new InPlaceConfigurationSource();

source.Add(typeof(ActiveRecordBase), properties);

ActiveRecordStarter.Initialize(source, typeof(Blog), typeof(Post));
```

`InPlaceConfigurationSource` is only recommended in two situations. You are getting acquanted with ActiveRecord or your system has a custom configuration support and you want to integrate wit it.

### XmlConfigurationSource

You can also read the configuration from a Xml file. The schema is documented in [XML Configuration Reference](xml-configuration-reference.md).

```csharp
using Castle.ActiveRecord.Framework.Config;

XmlConfigurationSource config = new XmlConfigurationSource("ARConfig.xml");

ActiveRecordStarter.Initialize(config, typeof(Blog), typeof(Post));
```

:warning: **Warning:** If a non-absolute filename is use like in the example above, the file will be searched based on the working directory. Usually the working directory is the bin folder.

The `XmlConfigurationSource` is the better approach if you want to externalize the configuration in a file with an exclusive purpose of holding the ActiveRecord configuration.

### ActiveRecordSectionHandler

With the `ActiveRecordSectionHandler` you can use the configuration file associated with the `AppDomain` (for example the web.config). The schema is documented in [XML Configuration Reference](xml-configuration-reference.md).

```csharp
using Castle.ActiveRecord.Framework.Config;

IConfiguration config = ActiveRecordSectionHandler.Instance;

ActiveRecordStarter.Initialize(config, typeof(Blog), typeof(Post));
```

:warning: **Warning:** If a section is not found an exception will be thrown.
Loading

0 comments on commit 6ad46de

Please sign in to comment.