Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.DataAccess.ADOHelper/DataAdapterBase.cs @ 1488

Last change on this file since 1488 was 1488, checked in by svonolfe, 15 years ago

Updated transaction management (#527)

File size: 7.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Data;
24using System.Collections.Generic;
25using System.Text;
26using System.Linq;
27using System.Threading;
28using HeuristicLab.DataAccess.Interfaces;
29
30namespace HeuristicLab.DataAccess.ADOHelper {
31  public abstract class DataAdapterBase<AdapterT, ObjT, RowT>
32    where AdapterT : new()
33    where RowT : System.Data.DataRow
34    where ObjT : IPersistableObject, new() {
35
36    private ISession session;
37
38    private IDataAdapterWrapper<AdapterT, ObjT, RowT> dataAdapter;
39
40    private static Mutex lockersMutex =
41      new Mutex();
42
43    private static IDictionary<object, Mutex> lockers =
44      new Dictionary<object, Mutex>();
45
46    private static IDictionary<object, int> lockCount =
47      new Dictionary<object, int>();
48
49    protected DataAdapterBase(
50      IDataAdapterWrapper<AdapterT, ObjT, RowT> dataAdapter) {
51      this.dataAdapter = dataAdapter;
52    }
53
54    protected void LockRow(object id) {
55      Mutex rowLock = null;
56
57      /////begin critical section////
58      lockersMutex.WaitOne();
59
60      if (!lockers.ContainsKey(id)) {
61        lockers[id] = new Mutex();
62        lockCount[id] = 0;
63      }
64      rowLock = lockers[id];
65      lockCount[id]++;
66     
67      lockersMutex.ReleaseMutex();
68      /////end critical section////
69
70      rowLock.WaitOne();
71    }
72
73    protected void UnlockRow(object id) {
74      Mutex rowLock = lockers[id];
75      rowLock.ReleaseMutex();
76
77      /////begin critical section////
78      lockersMutex.WaitOne();
79
80      lockCount[id]--;
81      if (lockCount[id] == 0)
82        lockers.Remove(id);
83
84      lockersMutex.ReleaseMutex();
85      /////end critical section////
86    }
87   
88    protected AdapterT Adapter {
89      get {
90        return dataAdapter.TransactionalAdapter;
91      }
92    }
93
94    public ISession Session {
95      get {
96        return this.session;
97      }
98
99      set {
100        this.session = value;
101        this.dataAdapter.Session = value;
102      }
103    }
104
105    public object InnerAdapter {
106      get {
107        return this.Adapter;
108      }
109    }
110
111    #region Abstract methods
112    protected abstract RowT ConvertObj(ObjT obj, RowT row);
113
114    protected abstract ObjT ConvertRow(RowT row, ObjT obj);
115    #endregion
116
117    protected delegate IEnumerable<RowT> Selector();
118
119    protected ObjT Convert(RowT row, ObjT obj) {
120      try {
121        obj = ConvertRow(row, obj);
122        return obj;
123      }
124      catch (DeletedRowInaccessibleException) {
125        return default(ObjT);
126      }
127      catch (RowNotInTableException) {
128        return default(ObjT);
129      }
130    }
131
132    protected RowT FindSingleRow(Selector selector) {
133      RowT row = default(RowT);
134
135      IEnumerable<RowT> found =
136        selector();
137
138      if (found.Count<RowT>() == 1)
139        row = found.First<RowT>();
140
141      return row;
142    }
143
144    protected ObjT FindSingle(Selector selector) {
145      ITransaction trans =
146       session.GetCurrentTransaction();
147      bool transactionExists = trans != null;
148      if (!transactionExists) {
149        trans = session.BeginTransaction();
150      }
151
152      try {
153        RowT row = FindSingleRow(selector);
154
155        ObjT result;
156        if (row != null) {
157          ObjT obj = new ObjT();
158          obj = Convert(row, obj);
159
160          result = obj;
161        } else {
162          result = default(ObjT);
163        }
164
165        return result;
166      }
167      finally {
168        if (!transactionExists && trans != null) {
169          trans.Commit();
170        }
171      }
172    }
173
174    protected ICollection<ObjT> FindMultiple(Selector selector) {
175      ITransaction trans =
176       session.GetCurrentTransaction();
177      bool transactionExists = trans != null;
178      if (!transactionExists) {
179        trans = session.BeginTransaction();
180      }
181
182      try {
183        IEnumerable<RowT> found =
184          selector();
185
186        IList<ObjT> result =
187          new List<ObjT>();
188
189        foreach (RowT row in found) {
190          ObjT obj = new ObjT();
191          obj = Convert(row, obj);
192          if (obj != null)
193            result.Add(obj);
194        }
195
196        return result;
197      }
198      finally {
199        if (!transactionExists && trans != null) {
200          trans.Commit();
201        }
202      }     
203    }
204
205    protected virtual RowT GetRowById(Guid id) {
206      return FindSingleRow(
207        delegate() {
208          return dataAdapter.FindById(id);
209        });
210    }
211
212    protected virtual void doUpdate(ObjT obj) {
213      if (obj != null) {
214        RowT row = null;
215        Guid locked = Guid.Empty;
216
217        if (obj.Id != Guid.Empty) {
218          LockRow(obj.Id);
219          locked = obj.Id;
220
221          row = GetRowById(obj.Id);
222        } else {
223          obj.Id = Guid.NewGuid();
224        }
225
226        if (row == null) {
227          row = dataAdapter.InsertNewRow(obj);
228        }
229
230        if (locked == Guid.Empty) {
231          LockRow(obj.Id);
232          locked = obj.Id;
233        }
234
235        ConvertObj(obj, row);
236        dataAdapter.UpdateRow(row);
237
238        UnlockRow(locked);
239      }
240    }
241
242    public void Update(ObjT obj) {
243      ITransaction trans =
244        session.GetCurrentTransaction();
245      bool transactionExists = trans != null;
246      if (!transactionExists) {
247        trans = session.BeginTransaction();
248      }
249
250      try {
251        doUpdate(obj);
252      }
253      finally {
254        if (!transactionExists && trans != null) {
255          trans.Commit();
256        }
257      }
258    }
259
260    public virtual ObjT GetById(Guid id) {
261      return FindSingle(delegate() {
262        return dataAdapter.FindById(id);
263      });
264    }
265
266    public virtual ICollection<ObjT> GetAll() {
267      return new List<ObjT>(
268        FindMultiple(
269          new Selector(dataAdapter.FindAll)));
270    }
271
272    protected virtual bool doDelete(ObjT obj) {
273      bool success = false;
274
275      if (obj != null) {
276        LockRow(obj.Id);
277
278        RowT row =
279          GetRowById(obj.Id);
280
281        if (row != null) {
282          row.Delete();
283          dataAdapter.UpdateRow(row);
284
285          success = true;
286        }
287
288        UnlockRow(obj.Id);
289      }
290
291      return success;
292    }
293
294    public bool Delete(ObjT obj) {
295      ITransaction trans =
296        session.GetCurrentTransaction();
297      bool transactionExists = trans != null;
298      if (!transactionExists) {
299        trans = session.BeginTransaction();
300      }
301
302      try {
303        return doDelete(obj);
304      }
305      finally {
306        if (!transactionExists && trans != null) {
307          trans.Commit();
308        }
309      } 
310    }
311  }
312}
313
Note: See TracBrowser for help on using the repository browser.