Makale Özeti

Makalemin bu ikinci kısmında sizlerle beraber DataTable ın barındırdığı GetChanges,AcceptChanges,RejectChanges metodlarının bir collection için uygulamasının ne şekilde yapılacağını inceleyeceğiz. Bunun için bir önceki makalemde yazmış olduğumuz MyCollection isimli CollectionBase üzerinden devam ediyor olacağız. Amacımız Collection'ın içindeki her bir entity nesnesinin state ini tutmak, silinmiş, update edilmiş, yeni eklenmiş veya database den çekildiği gibi duran Nesnelerimizi collection içinden tek bir metodla çekebilmek veya Collection üzerinde yapılan değişikliklerin tamamını kabul edip Collectionu o hale getirmek yada değişiklikleri kabul etmeyip en son kabul edildiği hale tek bir metodla geri dönebilmek.

Makale

            Merhabalar
   
            Makalemin bu ikinci kısmında sizlerle beraber DataTable ın barındırdığı GetChanges,AcceptChanges,RejectChanges metodlarının bir collection için uygulamasının ne şekilde yapılacağını inceleyeceğiz. Bunun için bir önceki makalemde yazmış olduğumuz MyCollection isimli CollectionBase üzerinden devam ediyor olacağız. Amacımız Collection'ın içindeki her bir entity nesnesinin state ini tutmak, silinmiş, update edilmiş, yeni eklenmiş veya database den çekildiği gibi duran Nesnelerimizi collection içinden tek bir metodla çekebilmek veya Collection üzerinde yapılan değişikliklerin tamamını kabul edip Collectionu o hale getirmek yada değişiklikleri kabul etmeyip en son kabul edildiği hale tek bir metodla geri dönebilmek.

            Bunun için yazmamız gerekn kodları adım adım inceleyecek olursak;

      public class MyCollection<T> : CollectionBase, IList<T>
      {
            public
MyCollection()
            {
            }
           
public enum ObjectStates
            {
                  Added = 0,
                  Deleted = 2,
                  Updated = 4,
                  Orginal = 8
            }
            private
ArrayList mOrginalArrayList = new ArrayList();
           
Dictionary<T, ObjectStates> InnerDictionary = new Dictionary<T, ObjectStates>();


            Bu kısımda tanımlamış olduğumuz ismini MyCollection verdiğimiz classımızı CollectionBase classından türeteceğiz ve IList interface’inin Generic tipini inherit ederek kullanacağız. Bununla ilgili bilgi bir önceki makalede verilmişti.Ancak adı mOrginalArrayList olan ve tipi ArrayList olan değişkenimizde ise collectionımızın en son save edilen halini saklıyor olacağız. Yani burası ileride AcceptChanges metodumuzda collectionu kaydedeceğimiz veya RejectChanges metodunda geriye döneceğimiz collectionu barındıran değişken olacaktır. InnerDictionary ise Collectionumuzdaki nesnelerin state lerini tutacağımız ve key-value pairlerinden olauşan Generic bir dictionarydir. Bu dıctıonary de key'ler nesnelerimiz value lar ise state'leri olacaktır. ObjectStates enumurator u ise nesnelerimizin state lerini takip edebilmemiz için yazılmuş bir enumaratördür.
 

            public void SetDataFromReader(DbDataReader dr)
            {
                  Type
assemblyType = typeof(T).Assembly.GetType(typeof(T).FullName);
                  while
(dr.Read())
                  {
                        T a = (T)Activator.CreateInstance(assemblyType);
                        foreach
(PropertyInfo pi in assemblyType.GetProperties())
                        {
                              if
(dr[pi.Name] != null)
                              {
                                    pi.SetValue(a, dr[pi.Name], null);
                              }
                        }
                        InnerList.Add(a);
                        InnerDictionary.Add(a, ObjectStates.Orginal);
                  }
                  mOrginalArrayList = (ArrayList)InnerList.Clone();
            }

            Bu metod tam olarak bir önceki makalemin konusu olduğundan burada bu metodun ne iş yaptığını açıklama gereği duymuyorum ancak dikkat edilmesi gereken eklenen her nesnenein aynı zamanda Dıctıonary içine ObjectState i Orginal olacak şekilde yüklenmesi ve tüm nesnelerin yüklenmesinin bittiği zaman ise daha önceden tanımladığımız mOrginalArrayList adındaki ArrayListe collectionumuzun bir klonunu yaratılmasıdır.
 

public ArrayList GetChanges(ObjectStates objState)
{
      ArrayList
returnList = new ArrayList();
      foreach
(KeyValuePair<T, ObjectStates> item in InnerDictionary)
      {
            if
(item.Value == objState)
            {
                  returnList.Add(item.Key);
            }
      }
      return
returnList;
}

            GetChanges metodunu inceleyecek olursak bu metod bizden parametre olarak ObjectState istemektedir ve InnerDictionary ismi Dictionary içindeki tüm kayıtlara bakarak value su parametre olarak verdiğimiz ObjectState'e eşit olanları returnList ismiyle yarattığımız yeni bir Arrayliste atamakta ve bu ArrayList i bize geri döndürmektedir. Bu sayede istediğimiz ObjectState e sahip olan nesneleri Collectiondan alabilmekteyiz. Bu Stateleri nasıl belirleyeceğimizi ise biraz sonra göreceğiz.
 

public void AcceptChanges()
      {
            mOrginalArrayList.Clear();
            InnerDictionary.Clear();
            foreach
(T item in InnerList)
            {
                  mOrginalArrayList.Add(item);
                  InnerDictionary.Add(item, ObjectStates.Orginal);
            }
      }

            AcceptChanges metodunda collectionumzdaki tüm nesnelerin statelerini Orginal yapıyoruz bunu yapmamızdaki amac değişiklikleri kabul edip bundan sonra Collectiondaki nesnelerimizin orjinal hallerinin bu olacağını belirttiğimiz metod olmasıdır. Bunu yaparken izlediğimiz yol ise InnerDıctıonary'i ve mOrginalArrayList'i temizlemek ve şu anki verilerle tekrar doldurmak şeklindedir.
 

public void RejectChanges()
      {
            InnerList.Clear();
            InnerDictionary.Clear();
            foreach
(T item in mOrginalArrayList)
            {
                  InnerList.Add(item);
                  InnerDictionary.Add(item, ObjectStates.Orginal);
            }
      }

            RejectChanges metodunda ise en son AcceptChanges yapıldığı ana veya AcceptChanges yapılmamışsa Datanın ilk çekildiği andaki haline geri dönmemizi sağlayacak metoddur. Bu metodun çalışma amntığı ise InnerList'i ve InnerDictionar i tamamen temizlemek ve mOrginalArrayList'in bir kopyasını bu değişkenlere atamaktır.
 

            #region IList<T> Members

            public
int IndexOf(T item)
            {
                  return InnerList.IndexOf(item);
            }

            Collectionumuzun IndexOf metodunu InnetList değişkeninin IndexOf  metoduyla kullanabileceğimiz için bu metoda kişiselleştirilmiş bir kod yazmıyoruz.
 

public void Insert(int index, T item)
{
      InnerList.Insert(index, item);
      InnerDictionary.Add(item, ObjectStates.Added);
}

            Collectionumuzun Insert metodunda ise InnerLit değişekinine insert yapıyoruz. Ancak bunun yanısıra InnerDictionary değişkenimize ise key olarak eklenen nesneyiö value olarak ise Added Olarak State'ini ekliyoruz. Bu sayede ileride yeni eklenen nesnelerimizi GetChanges metodumuz ile çekebileceğiz.
 

public T this[int index]
{
      get

      {
            return
(T)InnerList[index];
      }
      set

      {
            T item = (T)InnerList[index];
            ObjectStates
state;
            if
(InnerDictionary[item] == ObjectStates.Added)
            {
                  state = ObjectStates.Added;
            }
            else

            {
                  state = ObjectStates.Updated;
            }
            InnerDictionary.Remove(item);
            InnerDictionary.Add(value, state);
            InnerList[index] = value;
      }
}

#endregion

            Collectionumuzun this metodunda ise update işlemleri yapıldığından dolayı bu property nin set metodunda yer alan kodu InnerList'in aynı isimdeki propertysini kullanabiliyoruz. Ancak burada bakmamız gereken önemli bir nokta bu metodda yeni değeri verilen nesnenin daha önceden State'inin Added mi yoksa Orginal mı olduğudur. Eğer daha önceki State'i Added ise Update işleminin hiçbir etkisi olmayacak ve state'i added olarak kalacaktır. Ancak State'i orginal ise artık State'i updated olarak değişecektir. Bunu ise eski nesnemizi InnerDictionay'den silip yeni nesnemizi yeni State'i ile InnerDictionary'e ekleyerek yapabiliriz.
 

#region ICollection<T> Members

      public
void Add(T item)
      {
            InnerList.Add(item);
            InnerDictionary.Add(item, ObjectStates.Added);
      }

            Collectionumuzun Add Metodu ise Insert metoduyla aynıdır.
 

public bool Contains(T item)
      {
            return
InnerList.Contains(item);
      }

            Collectionumuzda yer Alan Contains metodu ise InnerList'i Contains metodu ile aynıdır.
 

public void CopyTo(T[] array, int arrayIndex)
      {
            InnerList.CopyTo(array, arrayIndex);
      }

public bool IsReadOnly
      {
            get
{ return InnerList.IsReadOnly; }
      }

            CopyTo metodu ve IsReadOnly property'si ise InnerList'in metodlarının direkt kullanılabileceği diğer metodlardır.
 

public bool Remove(T item)
      {
            if
(InnerList.Contains(item))
            {
                  ObjectStates
state = InnerDictionary[item];
                  if
(state == ObjectStates.Added)
                  {
                        InnerDictionary.Remove(item);
                  }
                  else
if (state == ObjectStates.Orginal)
                  {
                        InnerDictionary[item] = ObjectStates.Deleted;
                  }
                  else
if (state == ObjectStates.Updated)
                  {
                        InnerDictionary[item] = ObjectStates.Deleted;
                  }
                  InnerList.Remove(item);
                  return
true;
            }
            return
false;
      }


      #endregion

            Gelelim en çok sınama yapacağımız meod olan Remove metoduna, bu metod parametre olarak generic tipimizden bir nesne alıyor ve bunu collection içinden siliyor. Ancak bunu collection içinden silerken InnerDictionay'de ise State'i Added Olarak duruyorsa yani en son kaydedildikten sonra eklenmiş bir nesne ise u nesnenin silinmesi durumunda Collectiona hiç eklenmemiş gibi davranılabileceği için InnerDictionay'den direkt silebiliriz, Ancak diğer durumlarda ise InnerDictionary'de bulunan nesnenin durumunu Deleted olarak değiştirmek gereklidir.
 

            #region IEnumerable<T> Members

            public
new IEnumerator<T> GetEnumerator()
            {
                  return
(IEnumerator<T>)InnerList.GetEnumerator();
            }


            #endregion

      }

            Bu kısımda ise IEnumerable interface'inin metodu olan GetEnumerator metodunun InnerList'in GetEnumerator() metodu kullanarak nasıl geliştirilebileceğini görüyoruz.

            Bu makalede sizlerle birlikte state tutabilen bi collectionun nasıl geliştirilebileceğini, ve bir collectionun hangi Interface'ler kullanılarak nasıl yaratılabileceğini incelemiş olduk. Kullanılabiliritesi yüksek olan bu metod umarım sizler içinde faydalı olmuştur.

            Bu dizinin bundan sonraki makalesinde yarattığımız bu metodları kullanabileceğimiz bir örneği inceleyeceğiz.

Tamer ÖZ

oztamer@hotmail.com
tamer.oz@yazgelistir.com
oztamer@hotmail.com
Ozel Bir Collection III - Verinin State'ini Tutmak

Ozel Bir Collection I - Kolay Veri Doldurma