-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
35 changed files
with
4,571 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
Oops, something went wrong.