اگر با SQL Server كار كرده باشيد حتما با مفهوم و امكان Computed columns (فيلدهاي محاسبه شده) آن آشنايي داريد. چقدر خوب ميشد اگر اين امكان براي ساير بانكهاي اطلاعاتي كه از تعريف فيلدهاي محاسبه شده پشتيباني نميكنند، نيز مهيا ميشد. زيرا يكي از اهداف مهم استفادهي صحيح از ORMs ، مستقل شدن برنامه از نوع بانك اطلاعاتي است. براي مثال امروز ميخواهيم با MySQL كار كنيم، ماه بعد شايد بخواهيم يك نسخهي سبكتر مخصوص كار با SQLite را ارائه دهيم. آيا بايد قسمت دسترسي به داده برنامه را از نو بازنويسي كرد؟ اينكار در NHibernate فقط با تغيير نحوهي اتصال به بانك اطلاعاتي ميسر است و نه بازنويسي كل برنامه (و صد البته شرط مهم و اصلي آن هم اين است كه از امكانات ذاتي خود NHibernate استفاده كرده باشيد. براي مثال وسوسهي استفاده از رويههاي ذخيره شده را فراموش كرده و به عبارتي ORM مورد استفاده را به امكانات ويژهي يك بانك اطلاعاتي گره نزده باشيد).
خوشبختانه در NHibernate امكان تعريف فيلدهاي محاسباتي با كمك تعريف نگاشت خواص به صورت فرمول مهيا است. براي توضيحات بيشتر لطفا به مثال ذيل دقت بفرمائيد:
در ابتدا كلاس كاربر تعريف ميشود:
using System;
using NHibernate.Validator.Constraints;
namespace FormulaTests.Domain
{
public class User
{
public virtual int Id { get; set; }
[NotNull]
public virtual DateTime JoinDate { set; get; }
[NotNullNotEmpty]
[Length(450)]
public virtual string FirstName { get; set; }
[NotNullNotEmpty]
[Length(450)]
public virtual string LastName { get; set; }
[Length(900)]
public virtual string FullName { get; private set; } //از طريق تعريف فرمول مقدار دهي ميگردد
public virtual int DayOfWeek { get; private set; }//از طريق تعريف فرمول مقدار دهي ميگردد
}
}
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;
namespace FormulaTests.Domain
{
public class UserCustomMappings : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
mapping.Id(u => u.Id).GeneratedBy.Identity(); //ضروري است
mapping.Map(x => x.DayOfWeek).Formula("DATEPART(dw, JoinDate) - 1");
mapping.Map(x => x.FullName).Formula("FirstName + ' ' + LastName");
}
}
}
اكنون اگر Fluent NHibernate را وادار به توليد اسكريپت متناظر با اين دو كلاس كنيم حاصل به صورت زير خواهد بود:
create table Users (
UserId INT IDENTITY NOT NULL,
JoinDate DATETIME not null,
FirstName NVARCHAR(450) not null,
LastName NVARCHAR(450) not null,
primary key (UserId)
)
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" mutable="true"
name="FormulaTests.Domain.User, FormulaTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="Users">
<id name="Id" type="System.Int32" unsaved-value="0">
<column name="UserId" />
<generator class="identity" />
</id>
<property name="DayOfWeek" formula="DATEPART(dw, JoinDate) - 1" type="System.Int32" />
<property name="FullName" formula="FirstName + ' ' + LastName" type="System.String" />
<property name="JoinDate" type="System.DateTime">
<column name="JoinDate" />
</property>
<property name="FirstName" type="System.String">
<column name="FirstName" />
</property>
<property name="LastName" type="System.String">
<column name="LastName" />
</property>
</class>
</hibernate-mapping>
var list = session.Query<User>.ToList();
foreach (var item in list)
{
Console.WriteLine("{0}:{1}", item.FullName, item.DayOfWeek);
}
select
user0_.UserId as UserId0_,
user0_.JoinDate as JoinDate0_,
user0_.FirstName as FirstName0_,
user0_.LastName as LastName0_,
DATEPART(user0_.dw, user0_.JoinDate) - 1 as formula0_, --- همان فرمول تعريف شده است
user0_.FirstName + ' ' + user0_.LastName as formula1_ ---از طريق فرمول تعريف شده حاصل گرديده است
from
Users user0_