1. Bilgi.Utils
Bilgi.Utils projesi altında temel olarak aşağıdaki kategorilerde gruplandırılabilecek class’lar yer almaktadır:
1.1. Bilgi.Utils.Hibernate
Bu projenin içinde NHibernate’in projelerimizde kullanımını kolaylaştırmak için tasarlanmış bazı classlarla, tasarımlarımızı benzer tutmak için geliştirilmiş interfaceler yer almaktadır.
NHSessionManager
Bu class singleton bir class’tır. Doğrudan NHibernate session objesine ulaşmamıza gerek kalmadan hibernate session yönetimi ile ilgili temel işlevleri sunmaktadır. İki modda çalıştırılabilir
Session yönetimi Web (http request bazında session) ve WinForm uygulamalarında (her form için ayrı session) tercihe göre farklılık gösterebilir. Ancak temel fikir singleton NHSessionManager class’ının kendisini kullanan data access objelerine her zaman hazır bir session instance’ı vermesidir. NHSessionManager class’ının data access objelerine sunacağı session objesinin ne olacağına Web modunda çalıştırılırken doğrudan programcı tarafından karar verilemez, NHSessionManager bir hibernate session objesi hazırlayarak kullanıma sunacaktır. Ancak WinForm modunda çalıştırıldığında CreateSession() ve SetCurrentSession() prosedürleri ile, örneğin her formun kendi session’unu kendi içinde taşıması ve form aktif hale geldikçe NHSessionManager.SetCurrentSession() çağırısı ile data access objelerine sunulacak session objesinin dışarıdan belirlenmesi sağlanabilir.
Bu iki farklı session yönetimi yaklaşımının kullanılmasının nedeni hibernate’in object caching yöntemi ile yakından ilgilidir. Hibernate gözü ile olaya bakıldığında session objesi birincil ve kullanılması zorunlu cache olarak değerlendirilmekte ve hibernate tarafından manage edilen tüm objeler grafları ile birlikte (taşıdıkları diğer obje referansları ve referansların taşıdıkları referanslar … ) zamanı ve yeri geldikçe (thanks to reflection) session’a yüklenmektedir. Bu nedenle özellikle çok fazla sayıda objenin uzun süreli olarak session’da tutulması özellikle winform uygulamalarımızda gözle görülür bir performans sorununa neden olacaktır.
WinForm uygulamalarında her forma ayrı hibernate session yaklaşımı kullanıldığında dikkat edilmesi gereken diğer bir nokta da bir formda instantiate edilmiş hibernate managed bir objenin başka bir forma geçilmesi ve ikinci formun kullandığı session kullanılarak persist edilmeye çalışılması durumunda Lazy Initialization hatası alınacaktır. Bu noktada bu tür taşımalarda 1) taşıyıcı başka objelere ve 2) taşınan objenin persist edileceği session kullanılarak sorgulanarak instance’ının alınması gerekecektir.
Hibernate kullanılırken bir objenin hayat döngüsünü ve durumunu tarif eden üç önemli kavram vardır. Bu kavramlar kısaca şu şekilde özetlenebilir.[1]
-
Transient: new ile yaratılmış objeler ilk etapta hibernate tarafından veritabanına persist edilemezler. Bu tür objelere herhangi bir referans kalmadığı zaman obje garbage collector tarafından temizlenir.
-
Persistent: Database identity’si olan ve yaratıldıktan sonra hibernate session objesinin örneğin save() metodu ile hibernate persistance manager’a iliştirilen veya session objesinin load() metodu ile instance’ı elde edilen objelerdir. Kısaca persistent objeler her zaman bir session’a iliştirilmişlerdir ve transactionlar kullanılarak veritabanına persist edilebilirler.
-
Detached: Persistant objelerin iliştirildiği session kapatıldığı zaman bu sessiona iliştirilmiş objeler referans edilmişlerse garbage collector tarafından temizlenemezler. Bu tür objelere detached objeler denir ve bu objeler herhangi bir zamanda yeni bir session’a ilişitirilebilir.
|
Hibernate In Action, B. Christian, G.King, Chapter-4.1
|
NHGenericDAO: IGenericDao, IDaoHelper
Hibernate kullanılarak veritabanından objelerin sorgulanması, değişikliklerin kaydedilmesi veya objelerin silinmesi için kullanılan generic bir classtır. Projelerimizdeki tüm data acess classları bu base classtan türetilerek save(), update(), delete(), GetById() ve Refresh() gibi ortak birtakım işlevler kazandırılmaktadır. Bu class IGenericDao interface’ini implemente etmektedir. Bu classın kullanımına evrak takip (DocTrace) projesinden şöyle bir örnek verilebilir.
/*
* Gelen evrağa (InDoc) özgü implemete edilmesi tasarlanan data acess
* metodları. IGenericDao interface’inden türetildiği için aynı zamanda
* IInDocDao interfacini implemete edecek class’ların IGenericDao
* interfacini de implemente etmesi sağlanmaktadır.
*/
public interface IInDocDao : IGenericDao<InDoc, int>
{
/// <summary>
/// Check if document has unsent deliveries of DeliveryType.Process
/// </summary>
/// <param name="InDoc"></param>
/// <returns></returns>
bool HasUnsentDeliveries( InDoc InDoc );
}
/*
* Gelen evrağa (InDoc) özgü data acess metodlarının gerçeklendiği class
* IInDocDao interface’ini implemente eder. IInDocDao interface’i
* IGenericDao interface’inden türetildiği için normalde IGenericDao
* üzerinde tanımlı metodların da InDocDao tarafından implemente edilmesi
* gerekecektir. Ancak biz NHGenericDao class’ı ile genel bir IGenericDao
* implementasyonu yaptığımız için InDocDao classını HNGenericDao classından
* türetip, IInDocDao interface’ini implemente ettiğini belirterek
* implementasyonumuzu tamamlamış oluruz
*/
public class InDocDao : NHGenericDao<InDoc, int>, IInDocDao
{
public bool HasUnsentDeliveries( InDoc InDoc )
{
ISession session = NHSessionManager.Instance.GetSession();
IQuery query = session.CreateQuery(" select count(*) "
+ " from InDocDelivery dd "
+ " where dd.DocInner = :InDoc"
+ " and dd.isSent = 0"
+ " and dd.deliveryType = :dType"
+ " and dd.isCanceled = 0");
query.SetEntity("InDoc", InDoc);
query.SetEnum("dType", DeliveryTypeEnum.Process);
int count = (int)query.UniqueResult();
if (count == 0)
{
return false;
}
else
{
return true;
}
}
}
1.2. Bilgi.Utils.NUnit
Projelerimizin unit testlerini yazarken yardımcı olacak class’ları içeren namespace. Şimdilik tek bir class bulunmaktadır.
HttpContextUnitTest
Web bağlamını simule etmek için kullanılabilecek olan yardımcı class.
1.3. Bilgi.Utils.General
Genel amaçlı yardımcı classları barındıran namespace.
CryptoHelper.cs
-
SymCryptography (public class ) : Simetrik şifreleme (geri dönüşümlü şifreleme) için kullanılan Rijandel, DES, TrippleDES ve RC2 algoritmalarının .NET implementasyonlarını utilize eden yardımcı class.
-
Hash (public class): MD5, SHA1, SHA256, SHA384 ve SHA512 gibi hash algoritmalarının .NET implementasyonlarını utilize eden yardımcı class.
EnumStrValAttr
Standard .NET Attribute classından türetilen yardımcı bir attribute class’ıdır. Bu class’ın amacı enumeration’lara string değerler assign edilmesini ve bu değerlerin sorgulanabilmesini sağlamaktır. Sorgulama için GetStrValue() statik metodunu içerir.
Örnek olarak evrak takip projesin testlerinde kullanılan ve veritabanı tablolarının her test öncesi temizlenmesini sağlayan DocDBCleanup classına göz atabilirsiniz.
public enum DocCleanupEnum
{
[EnumStrValAttr("delete OrgUserUnitRole")]
OrgUserUnitRole,
[EnumStrValAttr("delete OrgRoleAccessRight")]
OrgRoleAccessRight,
[EnumStrValAttr("delete OrgUserRole")]
OrgUserRole,
[EnumStrValAttr("delete OrgUser")]
OrgUser,
[EnumStrValAttr("delete OrgAccessRight")]
OrgAccessRight,
[EnumStrValAttr("delete OrgRole")]
OrgRole,
[EnumStrValAttr("delete OrgSysParam")]
OrgSysParam,
[EnumStrValAttr("delete OrgSystem")]
}
public class DocDBCleanup
{
/* ExecuteCleanup metoduna yukarıda tanımlı DocCleanupEnum dğerlerinden
* herhangi bir tanesini paremetre olarak geçerek ilgili enumla ifade
* edilen tablonun temizlenmesini sağlamak istiyoruz.
* Enumları tanımlarken her biri için ifade ettiği veya denk geldiği
* tabloyu silmek için kullanacağımız delete scriptini EnumStrValAttr
* olarak ekliyoruz.
*/
public void ExecuteCleanup( DocCleanupEnum EnumConst )
{
string deleteStr = DocDBCleanup.GetCleanupEnumValue(EnumConst);
if (deleteStr == String.Empty)
{
return;
}
SqlCommand cmd = new SqlCommand(deleteStr, (SqlConnection)_dbConn);
cmd.ExecuteNonQuery();
}
}
ImageUtils
Resimleri hibernate kullanarak veritabanına saklayabilmek için hibernate mappinglerinde ilgili resim objelerini byte[] olarak tanımlamamız gerekmektedir. Bu noktada standart .NET Image classını byte[] çevirebilecek (veritabanına saklamak için) ve byte[] Image’a (veritabanından okuyup Image olarak kullanabilmek için) çevirecek yöntemlere ihtiyacımız olacaktır. ImageUtils
public static byte[] ImageToByteArray(Image SourceImg)
public static Image ByteArrayToImage(byte[] SourceArray)
Statik prosedürleri ile bu işlemleri yapabilmemize yardımcı olmaktadır.
[1] Hibernate In Action, B. Christian, G.King, Chapter-4.1 , p. 116-119
2. Bilgi.Common
2.1 Bilgi.Common.Exceptions
17 adet genel exception class tanımının yer aldığı namsepacetir. Bu namespace’de yer alan tüm exception classları CommonException classından türetilmektedir. Bu exception classları projelerimizde kullandığımız ve bize özgü exception’ların merkezi olarak kolayca ayrıştırılabilmesini ve işelenebilmesini (örneğin e-mail atma) sağlamak amacıyla kullanılabilir.
/*
* Exceptionların atası olan class. Aynı zamanda burada belirtilen geçersiz
* işlem tipine uymayan geçersiz işlemlerde kullanılan class.
*/
public class CommonException: Exception
// Kullanıcı veya dış sistem giriş yapamadığı zaman kullanılabilir
public class LogOnFailedException : CommonException
/*
* Sistemlerimizde birebir aynı özellikte entitylere izin vermediğimiz
* koşullarda bu durumla karşılaşıldığından kullanılabilecek exception
*/
public class DuplicateEntityException : CommonException
/*
* Örneğin parent objesinin sadece constructorda set edilmesine izin
* verdiğimizi bunun dışındaki kod bloklarında değiştirme işlem yapılmaya
* çalışıldığında kullanılabilecek exception
*/
public class ParentNotModifiableException : CommonException
/*
* İlgilenilen item’ın ilgili bir listede bulunmadığı hata durumları için
* kullanılabilir.
*/
public class EntityListDoesNotContainItemException : CommonException
//İlgili alan değerinin geçerli olmadığı hata durumları için kullanılabilir.
public class FieldValueNotValidException : CommonException
// Sağlanan kriterin geçerli olmadığı hata durumlarında kullanılabilir.
public class ConstraintNotValidException : CommonException
/*
* Bir işlemin gerçekleştirilebilmesi için gerekli/yeterli ön koşulların
* sağlanamadığı hata durumlarında kullanılabilir.
*/
public class PrerequisiteNotMetException : CommonException
/*
* Parent-child ilişkilerde kendi parent’ı olarak atanma durumunda
* kullanılabilir.
*/
public class SelfAssignedAsParent : CommonException
// Geçersiz referans le ilgili hatalarda kullanılabilir.
public class InvalidEntityRefException : CommonException
/*
* Birden fazla defa aynı entity’nin kullanılmasını istemediğimiz
* hata durumlarında kullanılabilir.
*/
public class EntityContainedMultipleTimesException : CommonException
/*
* İki veya daha fazla child’in parent objelerinin aynı olmasını
* istediğimiz halde bu koşulun sağlanamadığı hata durumlarında
* kullanılabilir.
*/
public class ParentNotSameException : CommonException
//Aramalarda ilgili objenin bulunamadığını belirten hata
public class EntityNotFoundException : CommonException
/*
* Sağlanan değerin izin verilen alt-üst sınır dışında olması
* Durumunda kullanabiliriz.
*/
public class ValueOutOfRangeException : CommonException
/*
* Bir işlemin gerçekleştirilebilmesi için gerekli/yeterli ön koşulların
* sağlanamadığı hata durumlarında kullanılabilir.
*/
public class PreConditionNotMetException : CommonException
public class NullParamException : CommonException
/*
* Kullanıcının geçersiz veri girdiği ve geçersiz verinin kategorik olarak
* sınıflandırılamadığı genel hata durumlarında kullanılabilir.
*/
public class InvalidUserInputException : CommonException
2.2 Bilgi.Common.Interfaces
IInsertLoggable, IUpdateLoggable, IModifyLoggable
Hibernate Audit Logging (kaydı kim, ne zaman ekledi/güncelledi ) yapılabilmesi için IInterceptor[1] interfacini sunmaktadır. Bu interface’i projemizin ihtiyaçlarına göre implemente ederek persist edilen domain objelerimizi kimin ne zaman güncellediği/eklediği ile ilgili log bilgisi tutabiliriz. Bunun için
-
IInterceptor interface’ini implemente etmeli ve
-
Hibernate session’ı açarken IInterceptor interface’ini implemente eden objemizi parametre olarak geçmeliyiz.
Bu iki aşamadan sonra hibernate kullanarak güncellenen/eklenen objelere interceptor implementasyonumuzu kullanarak erişebiliriz.
IInsertLoggable, IUpdateLoggable ve IModifyLoggable interfaceleri aslında genel kullanıma uygun bir IInterceptor interface’ini implemente edebilmek için düşünülmüş yapılardır. Genel kullanıma yönelik geliştirdiğimiz interceptor class’ımız bu üç interface’i implemente eden objeler ile ilgili audit log tutabilme kabiliyetindedir. Interceptor classımız birebir proje bazında geliştirdiğimiz domain objelerimizi tanımaz bu objelerin ilgili interface’lerden herhangi birini implemente edip etmediğine göre üzerinde tanımlı operasyonları gerçekleştirir.
/*
* Hem veritabanına eklendiğinde hem de güncellendiğinde işlemin
* kim tarafından ve ne zaman yapıldığını bilmek istediğimiz domain
* objelerimizin implemente edeceği interface
*/
public interface IModifyLogable
{
int? SysCreatedBy { get; set;}
DateTime? SysCreatedOn { get; set; }
int? SysLastUpdatedBy { get; set;}
DateTime? SysLastUpdatedOn { get; set; }
}
/*
* Sadece veritabanına ekleme yapıldığında işlemin
* kim tarafından ve ne zaman yapıldığını bilmek istediğimiz domain
* objelerimizin implemente edeceği interface
*/
public interface IInsertLogable
{
int? SysCreatedBy { get; set;}
DateTime? SysCreatedOn { get; set; }
}
/*
* Veritabanında güncelleme yapıldığında işlemin
* kim tarafından ve ne zaman yapıldığını bilmek istediğimiz domain
* objelerimizin implemente edeceği interface
*/
public interface IUpdateLogable
{
int? SysLastUpdatedBy { get; set;}
DateTime? SysLastUpdatedOn { get; set; }
}
NOT: Her üç interface de işlemi gerçekleştiren kullanıcıya ilişkin ayrıntıların veritabanında bir tabloda bulunduğunu (örneğin Person) ve interface’i implemente eden domain objesinin veritabanı tablosunda ilgili kişinin kaydına işaret eden değeri taşıyan ve foreign key olarak nitelenebilecek bir kolonla ifade edildiğini varsaymaktadır.
Örnek interceptor implementasyonu için Bilgi.DocTrace.Utils projesindeki
public class DocAuditLogger:IInterceptor
classına bakınız.
IVersionedEntity
Projelerimize özgü domain objelerimizin hibernate tarafından tanımlanan managed versioning[2] yöntemini kullanabilecek şekilde tasarlanabilmesini sağlamak için kullanılan interfacetir. Bu interface’i implemente eden domain objelerimizin hibernate mapping’lerinde yapılacak bir tanımla objelerimiz her update edildiğinde veryion numarası otomatik olarak arttırılmakta, güncelleme için üretilen SQL update scriptlerinin where kısmında veritabanından alınan versiyon numarası kriter olarak kullanılmaktadır. Böylece bir kullanıcının veritabanından aldığı versiyonla güncellemenin gerçekleştiği andaki veritabanı kaydının versiyonu karşılaştırılmakta eğer versiyonlar farklı ise bir hata üretilerek güncellemenin gerçekleşmemesi sağlanmaktadır. Böylece farklı kullanıcıların aynı kaydı farklı anlarda güncelleyerek birbirinin değişikliklerini ezmemesi sağlanabilmektedir.
|
<?xml version='1.0' encoding='utf-8'?>
<hibernate-mapping
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns='urn:nhibernate-mapping-2.0'>
<class
name='Bilgi.DocTrace.Core.Incoming.Domain.InDoc, Bilgi.DocTrace.Core'
table='InDoc'>
<id name='ID'
column='InDocID'
unsaved-value='0'>
<generator class='identity' />
</id>
<version name='_version' column='Version' access='field' unsaved-value='0' type='Int64'/>
|
|
InDoc domain objemize ilişkin örnek hibernate mapping dosyası
|
[2] [2] Hibernate In Action, B. Christian, G.King, Chapter-5.3 , p. 169-171
2.2 Bilgi.Common Diğer
DomainObject
Projelerimize özgü domain objelerimizin türetildiği üzerinde object identity[1] kavramını karşılayan ve tipi ihtiyaca göre değiştirilebilen (generic olmasının altındaki temel neden, id’lerimiz int olabileceği gibi string veya longint de olabilmesi ihtimalidir.) base classtır. Bu class üzerinde IsTransient() dışında başka bir metod ve id alanı dışında başka bir property bulunmaz.
Bu class’ın kullanımına evrak takip projesinden (DocTrace) aşağıdaki UML kesiti örnek olarak verilebilir.
Interval
Herhangi bir tipten (int, string , DateTime) değer taşıyan başlangıç/bitiş tanımı yapabilmemizi sağlayan generic bir class.
PropertyHelper
Herhangi bir objenin property’lerini string olarak alıp incelememizi sağlamak için geliştirilmiş yardımcı bir class. Sadece aşağıdaki prosedürü içerir.
public static string GetObjectPropertyInfo(Object o)
LocalizedDescription
Standard .NET Attribute classından türetilen yardımcı bir attribute class’ıdır. Bu class’ın amacı enumeration’lara Türkçe ve İngilizce açıklamalar eklenebilmesini ve bu açıklamaların yürütme zamanında okunabilmesini sağlamaktır. Açıklamaları sorgulayabilmek için GetLocalizedDescription( Enum EnumConst ) statik prosedürünü içerir.
Bu attribute’un kullanımına evrak takip (DocTrace) projesinden aşağıdaki örnek verilebilir.
/*
* Evrağın durumunu belirten enum tanımları.
* Enum tanımları yapılırken LocalizedDescription attribute’u ile
* Türkçe ve İngilizce açıklamaları da belirtilmektedir.
* Bu açıklamalar daha sonra kullanıcıya listeleme yapılırken kullanılacak
*/
public enum InDocState
{
// This is not a persistent state
[LocalizedDescription("Tanımsız","Unspecifed")]
Undefined = 0,
/// <summary>
/// Evrak henüz işleme girmedi
/// </summary>
[LocalizedDescription("Başlangıç","Initial")]
Initial = 1,
/// <summary>
/// Evrak DocConsultant önünde dağıtımı vs için bekliyor
/// </summary>
[LocalizedDescription("Beklemede", "Waiting")]
Waiting = 2,
/// <summary>
/// Evrak ilgili birimlere GEREĞİ İÇİN dağıtıldı. Bu birimlerden
/// dağıtımlarını
/// okumaları ve göndermeleri bekleniyor
/// </summary>
[LocalizedDescription("Gereği İçin Dağıtıldı", "Delivered For Processing")]
DeliveredForProcessing = 3,
/// <summary>
/// Evrak ilgili birimlere BİLGİ İÇİN dağıtıldı. Bu birimlerden
/// dağıtımlarını
/// okumaları ve göndermeleri bekleniyor
/// </summary>
[LocalizedDescription("Bilgi İçin Dağıtıldı", "Delivered For Info")]
DeliveredForInfo = 4,
/// <summary>
/// Evrağın dağıtımının yapıldığı tüm birimler dağıtımlarını
/// okudu ve/ya gönderdi
/// </summary>
[LocalizedDescription("Dağıtımlar Toplandı", "Deliveries Collected")]
Collected = 5,
/// <summary>
/// Evrağın süreci tamamlandı
/// </summary>
[LocalizedDescription("Süreç Tamamlandı", "Workflow completed")]
Completed = 6
}
/*
* Evrak durumunu belirten enumlar kulllanıcının seçim yapmak için
* kullanacağı bir combobox’a doldurulurken basitçe names[i] kullanmayıp
* enum tanımında belirtilen ingilizce veya türkçe açıklamalar okunarak
* kullanılıyor
*/
private void FillDeliveryMethodCombo( )
{
cmbDeliveryMethod.Properties.Items.Clear();
cmbDeliveryMethod.Properties.Items.Add("<Geliş Tipi>");
string[] names = Enum.GetNames(typeof(DeliveryMethodEnum));
for (int i = 0; i < names.Length; i++)
{
Enum delEnum = (Enum)Enum.Parse(typeof(DeliveryMethodEnum));
string s = LocalizedDescription.GetLocalizedDescription(delEnum, names[i])
cmbDeliveryMethod.Properties.Items.Add(s);
}
cmbDeliveryMethod.SelectedIndex = 0;
}
3. Genel İpuçları
3.1. Projelerin Yapılandırılması
Projelerimizi temel olarak üç alt projeden oluşacak şekilde yapılandırılmalıdır.
-
Bilgi.XXX.Core: Domain classlarımızın, domain classlarımızın hibernate mappinglerinin ve data aceess interfacelerinin yer aldığı proje
-
Bilgi.XXX.Data: Data acess interfacelerinin implementasyonu olan classların yer aldığı proje
-
Bilgi.XXX.Test: Her class için unit testlerimizin yer aldığı proje.
Yukarıda tanımlanan yapılanmada XXX projemizin veya ürünümüzün tanıtıcı adıdır. Bu üç proje Class Library Projesi olarak Bilgi.XXX.sln’nin altında yaratılmalıdır.
NOT-1: Yukarıda belirtilen 3 temel alt projenin yanısıra geliştirme sırasında ihtiyaç duyacağımız yardımcı classları barındıracak Bilgi.XXX.Utils alt projesi ve/veya 3 temel alt projenin ortak kullandığı classları barındıracak olan Bilgi.XXX.Common isimli alt projeleriniz de olabilir.
NOT-2: Alt projelerinizi kendi içlerinde klasörler (namespace’ler) kullanarak mantıksal parçalara da bölebilirsiniz.
NOT-3: Bilgi.XXX.Core ve Bilgi.XXX.Data projelerini kullanan WinForm veya Web uygulamaları ayrı birer solution olarak geliştirilmelidir
[1] Hibernate In Action, B. Christian, G.King, Chapter-3.4, p. 87
3.2. Hibernate Mappingleri
Hibernate mapping dokümanları aslında birer xml dosyasıdır. Bu mappingler Bilgi.XXX.Core isimli projenizin altında map ettikleri classlarla aynı mantıksal gruplar altında bulundurulmalı ve isimleri de map ettikleri class’ı yansıtmalı. Örneğin InDoc classını map eden dosya InDoc.hbm.xml olarak isimlendirilmelidir.
Mappingler ile ilgili önemli ipuçlarından bir tanesi de bu dosyaların emedded resource olarak derlenmesi gereğidir. Embedded resource olarak derlenen mapping dosyaları hibernate ortamı tarafından ilave programlama çabasına gerek kalmadan çözümlenebilmektedir.
3.3. Recursive Referans İhtiyacı ve Çözümü: Castle
Bölüm 3.1’de anlatılan yapılandırmaya göre domain classları ve data access interfaceleri Bilgi.XXX.Core içinde yer alırken data acess interfacelerinin implementasyonları Bilgi.XXX.Data içinde yer almaktadır. Bilgi.XXX.Data projesi data acess interfacelerini implemente edeceği için Bilgi.XXX.Core projesine referansta bulunacaktır. Diğer yandan domain classlarında örneğin kullanıcı objesi yaratılırken verilen kullanıcı adının daha önce kullanılıp kullanılmadığı kontrolünün yapılması gerekebilmektedir. Bu tür sorgulamalar Bilgi.XXX.Data projesi içinde yer alan data access classları tarafından yapılmaktadır. Bu noktada domain classları da örnekte belirtilen türden sorgulamaları yapabilmek için data access objelerine ihtiyaç duyacaktır.
.NET circular referanslara izin vermediği için Bilgi.XXX.Core projesi Bilgi.XXX.Data projesine referansta bulunamayacaktır. Bu kısıtlamayı aşmak için