۱۳۸۹/۱۰/۲۸

سرويس جمع و مفرد سازي اسامي


اگر به Entity data model wizard در VS.Net 2010 دقت كرده باشيد، گزينه‌ي "Pluralize or singularize generated object names" نيز به آن اضافه شده است:



اين مورد از اين جهت حائز اهميت است كه عموما نام جداول در بانك اطلاعاتي، جمع است و نام كلاس متناظر ايجاد شده براي آن در كدهاي برنامه بهتر است مفرد باشد. براي مثال نام جدول، Customers است و نام كلاس آن بهتر است Customer تعريف گردد. به اين صورت كار كردن با آن توسط يك ORM با معناتر خواهد بود؛ زيرا زمانيكه يك وهله از شيء Customer ايجاد مي‌شود، فقط يك ركورد از بانك اطلاعاتي مد نظر است؛ در حاليكه يك جدول مجموعه‌اي است از ركوردها.
زبان انگليسي هم پر است از اسامي جمع و مفرد باقاعده و بي‌قاعده و كل عمليات با اضافه و حذف كردن يك s و يا es پايان نمي‌يابد؛ براي مثال phenomenon و phenomena را در نظر بگيرد تا Money و Moneys.
اين امكان مهيا شده توسط Entity Framework 4.0 يا همان EF v2 با برنامه نويسي هم قابل دسترسي است و در اسمبلي System.Data.Entity.Design.dll و فضاي نام System.Data.Entity.Design.PluralizationServices قرار گرفته است.
اين اسمبلي جزيي از دات نت 4 است و اگر آن‌را توسط گزينه‌ي Add references در VS.NET مشاهده نمي‌كنيد، علت آن است كه در تنظيمات پروژه جاري، گزينه‌ي Target framework بر روي Client profile قرار گرفته است كه بايد به دات نت 4 كامل تغيير يابد.
استفاده از آن هم به صورت زير است:

using System;
using System.Data.Entity.Design.PluralizationServices;
using System.Globalization;

namespace PluralizationServicesTest
{
class Program
{
static void Main(string[] args)
{
var service = PluralizationService.CreateService(CultureInfo.GetCultureInfo("en"));
Console.WriteLine(service.Pluralize("mouse"));
Console.WriteLine(service.IsPlural("phenomena"));
}
}
}

ملاحظات:
اين روش فعلا به زبان انگليسي محدود است و اگر Culture را به مورد ديگري تنظيم كنيد با خطاي "We don't support locales other than English yet" متوقف خواهيد شد.


روش ديگر:
كتابخانه‌ي سورس باز Castle ActiveRecord نيز داراي كلاسي است به نام Inflector كه براي همين منظور طراحي شده است:


كاربرد آن در Fluent NHibernate
در Fluent NHibernate كار نگاشت كلاس‌ها به جداول به صورت خودكار صورت مي‌گيرد و همچنين توليد ساختار بانك اطلاعاتي نيز به همين نحو مي‌باشد. اما مي‌توان توليد نام جداول را سفارشي نيز نمود. براي مثال از كلاس Book به صورت خودكار ساختار جدولي به نام Books را توليد كند:
using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.Instances;
using NHibernate.Helper.Toolkit;

namespace NHibernate.Helper.MappingConventions
{
public class TableNameConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
instance.Table(Inflector.Pluralize(instance.EntityType.Name));
}
}
}
و براي تزريق آن خواهيم داشت:

... = new AutoPersistenceModel()
.Where(...)
.Conventions.Setup(c =>c.Add<TableNameConvention>())
.AddEntityAssembly(...)
...