Devexpress XPO .Net platformu için geliştirilmiş bir ORM yazılımıdır. ORM yazılımlarının yaygınlığı ve alternatiflerinin çoğalması DevExpress firmasını bu yazılımı ücretsiz yapmaya itmiş ve doğal olarak bu da beraberinde kullanıcı kitlesinin artmasına neden olmuştur.
Devexpress XPO bir çok veritabanına destek vermekle birlikte özellikle küçük uygulamalar için hayati öneme sahip XML formatında verileri saklamanızı ve üzerinde işlemler yapmanızı sağlayan bir özelliğe de sahiptir.
Yani oluşturduğunuz obje yapılarına göre verilerini XML dosyasında tutmaya, yeni veriler oluşturmaya ve mevcut veriler üzerinde değişiklik yapmaya olanak sağlar. Küçük veriler için tasarlandığı için sorgulama süreçleri de çok hızlı çalışır.
Özetle XML dosylarında CRUD işlemlerini sorunsuzca yapmanıza olanak sağlar.
Bu makalemde Devexpress XPO ile XML veri katmanının nasıl oluşturulduğunu veri ekleme, düzenleme, listeleme işlemlerinin nasıl gerçekleştirildiğini örnek üzerinden anlatmaya çalışacağım.
Örneğimize geçmeden önce önemli bir konuyu açıklamakta fayda var: Eğer uygulamanız çok fazla veri yazma işlemleri yapacaksa alternatif teknolojileri örenğin Sqlite kullanmanızı tavsiye ederim. Devexpress'in desteklediği veritabanlarına buradaki listeden ulaşabilirsiniz.
Veri yazma ve düzenleme süreçlerinin çok az ve genelde verileri görüntüleme veya sorgulama işlemleriniz varsa, tablonuzdaki verilerin sayısı 10 bini geçmeyecekse XMLDataSet özelliğini tercih etmenizi öneririm.
Örnek proje olarak basit bir üyelik sistemi tasarlayacağız. Bunun için kullanıcılar, kişiler ve iletişim bilgilerinin tutulduğu tabloları oluşturacak, tabloya veriler yazacak ve tablodan belirli kriterlere göre veri sorgulayacağız. Arayüz tasarlamak bu makalenin konusu olmadığı için sadece arka plan işlemlerini yapacağız.
Örnek projemiz için console uygulaması oluşturdum ve proje sonundaki kodları github üzerinden de paylaştım. Projenin tamamını görmek isteyenler buradaki linkten projenin tamamına erişebilirler.
Projeyi oluşturduktan sonra Nuget'tan DevExpress.XPO kütüphanesini aşağıdaki resimdeki gibi ekliyoruz.
Not: Örnek proje .net Core ile oluşturduğum için en son sürümü projeye ekleyebiliyorum. Eğer .net Framework tercih edecekseniz buna uygun sürümü seçmeniz gerekiyor.
İkinci adımda tablolarımızı tasarlamak için sınıfları oluşturacağız.
Genel olarak ORM yazılımları ile çalışırken bir base class oluşturulur ve tüm tablolar bu tablodan türetilmiş olur. Böylece tüm tablolardaki benzer alanlar sabit bir yapıya dönüştürülmüş olur. Biz de örneğimizi bu base objeyi oluşturarak başlıyoruz.
using DevExpress.Xpo;
using System;
namespace DevExpressXpo.XmlDataSetEgitim
{
[NonPersistent]
public abstract class BaseObject : XPCustomObject
{
public BaseObject(Session session) : base(session)
{
}
public override void AfterConstruction()
{
base.AfterConstruction();
CreatedTime = DateTime.Now;
GUID = Guid.NewGuid().ToString();
}
[Key]
[Persistent("GUID")]
public string GUID { get; set; }
[Persistent("CREATED_TIME")]
public DateTime CreatedTime { get; set; }
}
}
BasObject sınıfımız abstract bir classdır ve bundan sonra oluşturacağımız tüm tablo sınıfları bu sınıftan türetilerek oluşturulacak. Dikkat ederseniz bu BaseObject sınıfı da XPCustomObject sınıfından türetilmiştir ve bu sınıf da "OptimisticLockField" alanı otomatik olarak eklenecektir.
BaseObject sınıfını tanımlarken bir kaç Devexpress Xpo'ya özgü Attribute tanımladık. Bunları da sırasıyla açıklayacak olursak:
NonPersitent Attribute bir XPO tablosu tasarlarken tablonun kalıcı olmayacağını, yani bu isimde tablo oluşturulmayacağını belirtmek için kullanılır. DevExpress XPO'da NonPersitent Attribute "best practice" kullanım olarak da tüm tabloların türeyeceği base sınıfı tanımlamak için kullanılır.
Key Attribute Bir özelliğin anahtar nitelik olacağını belirtmek için kullanılır. XML veri seti ile çalışırken otomatik id üreten bir sequence yapısı olmadığı için "best practice" olarak GUID üretilerek anahtar olarak kullanılır.
Not: XML veri seti de olsa Devexpress XPO tüm tablolar için bir anahtar seçmeği zorunlu kılar. Uygulama içinde bu anahtarı yönetmek bir çok durumda sorun yaratacağı için genelde bu şekilde anahtar üretme mekanizması kullanılır.
Persistent Attribute bir tablonun veya kolunun ismini belirtmek için kullanılır. XML veri setinde bunlar oluşturulacak olan tagların tanımlamasıdır. Genellikle alfa-numerik ve mümkün olduğu kadar Türkçe karakter kullanmadan tasarlama yapmanızı öneririm.
Size Attribute: Sql tabloları tasarlarken varchar tanımlamasının karşılığıdır. Eğer tanımlama yapmazsanız varsayılan değeri 100 olarak atanır ve bu bir çok durumda başınızı ağrıtabilir. Bu yüzden string kolonlar tasarlarken mutlaka Size Attribute'yi tanımlamaya özen gösterin.
Devexpress XPO'nun sahip olduğu diğer Attribute'ları kendi sayfasını ziyaret ederek araştıra bilirsiniz. Ama genel olarak kullanılanlar NonPersitent, Key, Persistent ve Size özelliklerini doğru şekilde kullanmak tablo tasarımı için çok önemli konudur.
Tablo tasarımı ile ilgili bu bilgilerden sonra sırayla tablolarımızı tasarlayabiliriz. İlk olarak People tablosunu tasarlayalım. Dikkat ederseniz tasarlayacağımız sınıf Person, Persistent attribute ile ismini tablo ismini belirtirken PEOPLE olarak tanımlıyoruz.
Kullanıcı sınıfını tanımlarken kullanıcı ve kişi tabloları arasında birebir ilişkinin de kurulduğunu göreceksiniz. Yani ilişkiler nesneler arasındaki ilişkileri kurmakla ilgilidir. Aynı zamanda bir kişinin birden fazla iletişim bilgisi olacağı için iletişim bilgisi ve kişi arasındaki ilişkiyi de 1-N ilişki olarak tasarlıyoruz. Eğer N-N ilişki olursa bu zaman da iki sınıfı bir araya getiren yeni sınıf oluşturmamız gerekecekti
using DevExpress.Xpo;
namespace DevExpressXpo.XmlDataSetEgitim
{
[Persistent("PEOPLE")]
public class Person : BaseObject
{
public Person(Session session) : base(session)
{
}
[Size(255)]
[Persistent("NAME")]
public string Name { get; set; }
[Size(255)]
[Persistent("SURNAME")]
public string Surname { get; set; }
}
}
Kullanıcı Sınıfı:
using DevExpress.Xpo;
namespace DevExpressXpo.XmlDataSetEgitim
{
[Persistent("USERS")]
public class User : BaseObject
{
public User(Session session) : base(session)
{
}
[Size(40)] // Size özellik belirtilmezse varsayılan olarak 100 yazılır. Bu durumda 100 karakterden fazla olan veriler için hata alırsınız.
[Persistent("USERNAME")]
public string Username { get; set; }
[Size(1000)]
[Persistent("PASSWORD")]
public string Password { get; set; }
[Persistent("PERSON_GUID")]
public Person Person { get; set; }
}
}
İletişim Bilgileri Sınıfı
using DevExpress.Xpo;
using System;
using System.Collections.Generic;
using System.Text;
namespace DevExpressXpo.XmlDataSetEgitim
{
[Persistent("COMMUNICATIONS")]
public class Communication : BaseObject
{
public Communication(Session session) : base(session)
{
}
[Persistent("COMMUNICATION_TYPE")]
public ECommunicationType CommunicationType { get; set; }
[Size(255)]
[Persistent("VALUE")]
public string Value { get; set; }
[Persistent("IS_ACTIVE")]
public bool IsActive { get; set; }
[Persistent("PERSON_GUID")]
public Person Person { get; set; }
}
}
ECommunicationType Enumu:
namespace DevExpressXpo.XmlDataSetEgitim
{
public enum ECommunicationType
{
Email = 1,
MobileNumber = 2,
HomePhoneNumber = 3,
Fax = 4
}
}
Sınıflarımızı ve doğal olarak tablolarımızı da oluşturduk. Daha doğrusu XPO gerçek XML verisini siz tabloları kullanmaya başladığınızda oluşturur. Yani nesne tasarlar ve kullanmazsanız sadece bir class olarak kalmaya devam eder.
Tabloları tasarladıktan sonra ikinci aşama verileri işlemeye başladığımız XmlDataSetManager sınıfıdır. Bu sınıfı verileri sorgulamak, yeni veriler oluşturmak, güncellemek ve silme işlemlerinden önce XML veritabanını yağa kaldıran temel sınıfıdır.
XmlDataSetManager sınıfı
using DevExpress.Xpo;
using DevExpress.Xpo.DB;
using DevExpress.Xpo.Metadata;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
namespace DevExpressXpo.XmlDataSetEgitim
{
public class XmlDataSetManager : Singleton<XmlDataSetManager>
{
private readonly object LockObject = new object();
private XmlDataSetManager()
{
}
public void Init()
{
SetDataLayer();
}
public Session GetNewSession()
{
var session = new Session(DataLayer);
return session;
}
private volatile IDataLayer _fDataLayer;
private IDataLayer DataLayer
{
get
{
SetDataLayer();
return _fDataLayer;
}
}
public XPClassInfo GetClassInfo(Type t)
{
return DataLayer.Dictionary.GetClassInfo(t);
}
private void SetDataLayer()
{
if (_fDataLayer == null)
{
lock (LockObject)
{
if (_fDataLayer == null)
{
_fDataLayer = GetDataLayer();
}
}
}
}
public void SetDataLayer(IDataLayer dataLayer)
{
_fDataLayer = dataLayer;
}
private IDataLayer GetDataLayer()
{
IDataLayer dl = null;
XPDictionary dict = new ReflectionDictionary();
string connectionPoolString = XpoDefault.GetConnectionPoolString(String.Format(@"XpoProvider=XmlDataSet;Data Source={0}\datasource.xml", Directory.GetCurrentDirectory()));
IDataStore store = XpoDefault.GetConnectionProvider(connectionPoolString, AutoCreateOption.DatabaseAndSchema);
dict.GetDataStoreSchema(typeof(BaseObject).Assembly);
dl = new ThreadSafeDataLayer(dict, store);
Session newSession = new Session(dl);
XpoDefault.Session = null;
Assembly executingAssembly = Assembly.GetExecutingAssembly();
Type[] array = executingAssembly.GetTypes().Where(t => t.IsSubclassOf(typeof(BaseObject))).ToArray();
newSession.UpdateSchema(array);
return dl;
}
}
}
XML veritabanı altapısını XmlDataSetManager sınıfı ile tanımladıktan sonra artık kişi, kullanıcı ve iletişim bilgileri oluşturma süreçlerine geçebiliriz. Klasik örnek de olsa web siteleri için uyelikte alınan temel bilgilere göre kişi, kullanıcı ve iletişim bilgisi verilerini oluşturacak kodları yazalım.
PersonManager Sınıfı
using DevExpress.Xpo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DevExpressXpo.XmlDataSetEgitim
{
public class PersonManager : Singleton<PersonManager>
{
private PersonManager() { }
public Person Create(Session session, string name, string surname)
{
var person = new Person(session)
{
Name = name,
Surname = surname
};
person.Save();
return person;
}
public List<Person> List(Session session)
{
return session.Query<Person>().ToList();
}
}
}
UserManager Sınıfı
using DevExpress.Xpo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DevExpressXpo.XmlDataSetEgitim
{
public class UserManager : Singleton<UserManager>
{
private UserManager()
{
}
public User Create(Session session, Person person, string username, string password)
{
var user = new User(session)
{
Person = person,
Password = password,
Username = username
};
user.Save();
return user;
}
public List<User> List(Session session)
{
return session.Query<User>().ToList();
}
}
}
CommunicationManager Sınıfı
using DevExpress.Xpo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DevExpressXpo.XmlDataSetEgitim
{
public class CommunicationManager : Singleton<CommunicationManager>
{
private CommunicationManager() { }
public Communication Create(Session session, Person person, ECommunicationType type, string value)
{
var communication = new Communication(session)
{
CommunicationType = type,
Value = value,
IsActive = true,
Person = person
};
communication.Save();
return communication;
}
public List<Communication> Get(Session session, string personGuid)
{
return session.Query<Communication>().Where(t => t.Person.GUID == personGuid).ToList();
}
}
}
Temel sınıflar yazdıktan sonra artık üyelik sınıfını yazabilir ve buradan yeni üye kaydını yapabiliriz.
SignUpManager Sınıfı
using DevExpress.Xpo;
using System;
using System.Collections.Generic;
using System.Text;
namespace DevExpressXpo.XmlDataSetEgitim
{
public class SignUpManager : Singleton<SignUpManager>
{
private SignUpManager() { }
public bool SignUp(string username, string password, string name, string surname, string email)
{
try
{
using (Session session = XmlDataSetManager.Instance.GetNewSession())
{
session.BeginTransaction();
var person = PersonManager.Instance.Create(session, name, surname);
var user = UserManager.Instance.Create(session, person, username, password);
var communication = CommunicationManager.Instance.Create(session, person, ECommunicationType.Email, email);
session.CommitTransaction();
}
return true;
}
catch (Exception)
{
//Log Exception
return false;
}
}
}
}
Not: Yukarıdaki örneklerde de gördüğünüz gibi sorgulama işlemlerini Linq To Sql kullanarak yapıyoruz. Linq To Sql ayrı bir konu olduğu için burada bu konuya girmiyorum. Ayrıca MoreLinq de kullanarak sorgularınızın kalitesini daha da artırabilirsiniz.
Farkında değilsiniz belki ama Devexpress XPO kullanarak bir XML veritabanı oluşturdunuz. Tablo oluşturmayı ve tablolara veri yazıp sorgulamayı da yapabilir durumdasınız. Tek eksik kalan örnek kullanımdı. Onu da aşağıdaki kod parçasında yeni bir üyelik yaparak konumuzu tamamlıyoruz.
using DevExpress.Xpo;
using System;
namespace DevExpressXpo.XmlDataSetEgitim
{
class Program
{
static void Main(string[] args)
{
XmlDataSetManager.Instance.Init();
Console.WriteLine("XmlDataSet initialized");
//SignUpManager.Instance.SignUp("agha_alizade", "123123", "Agha", "Alizade", "agha_alizade@outlook.com");
using (Session session = XmlDataSetManager.Instance.GetNewSession())
{
var communications = CommunicationManager.Instance.Get(session, "1ad116b3-93b0-4d72-a3ad-38185ab4b10a");
}
Console.ReadLine();
}
}
}
Sorularınız olursa yorumlar kısmından bana yazabilirsiniz.
Makalenin eksik kaldığını düşündüğünüz noktaları varsa bana yazabilirsiniz.
Yorumlar
Yorum Gönder