NTP Analyzer  0.8.2
Analyze the operation of time servers
SqlDatabaseMapper.cs
Go to the documentation of this file.
1 //
2 // Copyright (c) 2013-2017 Carsten Sonne Larsen <cs@innolan.net>
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 
22 using System;
23 using System.Collections.Generic;
24 using System.Data;
25 using System.Diagnostics.CodeAnalysis;
26 using System.Linq;
27 using System.Threading;
28 using Ntp.Analyzer.Data.Log;
29 using Ntp.Analyzer.Objects;
30 using Ntp.Common.Log;
31 using Ntp.Data;
32 using Ntp.Data.Log;
33 using Ntp.Data.Provider;
34 
35 namespace Ntp.Analyzer.Data.Sql
36 {
40  public abstract class SqlDatabaseMapper<T> : DataMapper<T>, ITableInitializer
41  where T : PersistentObject
42  {
43  protected SqlDatabaseMapper(LogBase log)
44  : base(log)
45  {
46  }
47 
48  // ReSharper disable once StaticMemberInGenericType
49  private static readonly AutoResetEvent InsertEvent = new AutoResetEvent(true);
50  private readonly Dictionary<int, T> items = new Dictionary<int, T>();
51  protected readonly object MapperLocker = new object();
52  private IDbConnection connection;
53  protected IDataReader Reader;
54  private bool tableFetched;
55 
56  protected IEnumerable<T> Content => items.Values;
57 
58  protected IDbCommand Command { get; private set; }
59 
60  protected abstract string TableName { get; }
61 
62  protected abstract string CreateSql { get; }
63 
64  protected abstract bool UseCache { get; }
65 
66  public T this[int id]
67  {
68  get
69  {
70  if (!UseCache)
71  throw new NotSupportedException(LogMessages.DatabaseCacheError);
72 
73  FetchTable();
74 
75  T item;
76 
77  lock (items)
78  {
79  item = items.ContainsKey(id) ? items[id] : null;
80  }
81 
82  return item ?? FetchExternal(id);
83  }
84  }
85 
86  [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")]
87  public void CheckTable()
88  {
89  string sql = SqlDatabaseFactory.Instance.PrepareCheckTableSql(TableName);
90  bool exists;
91 
92  try
93  {
94  Open();
95  Command.CommandText = sql;
96  Log.SqlExecute(Command.CommandText);
97  Reader = Command.ExecuteReader();
98  exists = Reader.Read();
99  }
100  finally
101  {
102  Close();
103  }
104 
105  if (exists)
106  {
107  Log.TableExists(TableName);
108  return;
109  }
110 
111  Log.CreateTable(TableName);
112 
113  try
114  {
115  Open();
116  Command.CommandText = SqlDatabaseFactory.Instance.PrepareCreateTableSql(CreateSql);
117  Log.SqlExecute(Command.CommandText);
118  Command.Prepare();
119  Command.ExecuteNonQuery();
120  }
121  finally
122  {
123  Close();
124  }
125  }
126 
127  public override IEnumerator<T> GetEnumerator()
128  {
129  FetchTable();
130  return Content.ToList().GetEnumerator();
131  }
132 
133  public void Save(T item)
134  {
135  if (item.NewObject)
136  {
137  Insert(item);
138 
139  if (UseCache)
140  {
141  AddItem(item);
142  }
143  }
144  else
145  {
146  Update(item);
147  }
148  }
149 
150  protected void AddItem(T item)
151  {
152  lock (items)
153  {
154  items.Add(item.Id, item);
155  }
156  }
157 
158  protected void Close()
159  {
160  connection?.Close();
161  connection = null;
162  InsertEvent.Set();
163  }
164 
165  protected IDbDataParameter CreateParameter(string name, object value)
166  {
167  return SqlDatabaseFactory.Instance.CreateParameter(name, value ?? DBNull.Value);
168  }
169 
170  protected virtual T FetchExternal(int id)
171  {
172  return null;
173  }
174 
175  protected abstract void Insert(T item);
176 
177  protected void Open()
178  {
179  InsertEvent.WaitOne();
180 
181  if (Reader != null && !Reader.IsClosed)
182  {
183  Reader.Close();
184  Reader = null;
185  }
186 
187  // TODO: Implement monitoring of database link
188  if (connection == null)
189  {
191  }
192 
193  if (connection.State == ConnectionState.Closed)
194  {
195  connection.Open();
196  }
197 
199  Command.Connection = connection;
200  }
201 
202  protected string PrepareInsertSql(string sql)
203  {
205  }
206 
207  protected virtual string PrepareSql(string sql)
208  {
210  }
211 
212  protected abstract void ReadContent();
213 
214  protected void RemoveItem(T item)
215  {
216  lock (items)
217  {
218  items.Remove(item.Id);
219  }
220  }
221 
222  protected abstract void Update(T item);
223 
224  private void FetchTable()
225  {
226  lock (MapperLocker)
227  {
228  if (tableFetched)
229  return;
230 
231  ReadContent();
232  tableFetched = true;
233  }
234  }
235  }
236 }
abstract IDbDataParameter CreateParameter(string name, object value)
abstract IDbCommand CreateCommand()
abstract string PrepareInsertSql(string sql)
Base class for ORM mappers. Can be used for mapping object stored in files, databases, etc.
Definition: DataMapper.cs:31
abstract string PrepareSql(string sql)
override IEnumerator< T > GetEnumerator()
Read all data from table in a sequential manner.
abstract string PrepareCreateTableSql(string sql)
static SqlDatabaseFactory Instance
abstract string PrepareCheckTableSql(string table)
abstract IDbConnection CreateConnection()
Base class for OR/M mappers. Can be used for mapping objects stored in SQL databases.
IDbDataParameter CreateParameter(string name, object value)