mirror of https://github.com/ogoun/Zero.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
511 lines
19 KiB
511 lines
19 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Data.SqlClient;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using ZeroLevel.Specification;
|
|
|
|
namespace ZeroLevel.MsSql
|
|
{
|
|
public class SqlDbRepository<T>
|
|
{
|
|
#region Fields
|
|
private readonly SqlDbMapper<T> _mapper;
|
|
private readonly SqlDbProvider _dbProvider;
|
|
#endregion
|
|
|
|
#region Ctors
|
|
public SqlDbRepository(SqlDbConnectionFactory connectionFactory, bool mapOnlyMarkedMembers = true)
|
|
{
|
|
_mapper = new SqlDbMapper<T>(mapOnlyMarkedMembers);
|
|
_dbProvider = new SqlDbProvider(connectionFactory);
|
|
if (false == SqlDbProvider.CheckDatabaseExists(connectionFactory.Server, connectionFactory.Base))
|
|
{
|
|
SqlDbProvider.CreateDatabase(connectionFactory.Server, connectionFactory.Base, null, null);
|
|
Thread.Sleep(5000);
|
|
}
|
|
VerifyDb();
|
|
Prebuilt();
|
|
}
|
|
|
|
public SqlDbRepository(string connectionString)
|
|
: this(new SqlDbConnectionFactory(connectionString))
|
|
{
|
|
}
|
|
|
|
public SqlDbRepository(string server, string database)
|
|
: this(new SqlDbConnectionFactory(server, database, null, null))
|
|
{
|
|
}
|
|
#endregion
|
|
|
|
#region Simple queries
|
|
public IEnumerable<T> Get()
|
|
{
|
|
using (var table = _dbProvider.ExecuteQueryDataTable(_getAllQuery))
|
|
{
|
|
return ConvertToEntitySet(table);
|
|
}
|
|
}
|
|
|
|
public T GetById<TId>(TId id)
|
|
{
|
|
if (null == id)
|
|
throw new ArgumentNullException(nameof(id));
|
|
using (var table = _dbProvider.ExecuteQueryDataTable(_getByIdQuery, new SqlParameter[]
|
|
{
|
|
new SqlParameter(_mapper.IdentityName, id)
|
|
}))
|
|
{
|
|
if (null != table && table.Rows.Count > 0)
|
|
{
|
|
return _mapper.Deserialize(table.Rows[0]);
|
|
}
|
|
}
|
|
throw new KeyNotFoundException(string.Format("Not found db record by identity field '{0}' with value {1}",
|
|
_mapper.IdentityName, id));
|
|
}
|
|
|
|
public IEnumerable<T> Get<TField>(string fieldName, TField value)
|
|
{
|
|
if (null == value)
|
|
throw new ArgumentNullException(nameof(value));
|
|
if (string.IsNullOrWhiteSpace(fieldName))
|
|
throw new ArgumentNullException(nameof(fieldName));
|
|
var query = string.Format(_getByFieldNameQuery, fieldName, fieldName);
|
|
using (var table = _dbProvider.ExecuteQueryDataTable(query, new SqlParameter[]
|
|
{
|
|
new SqlParameter(fieldName, value)
|
|
}))
|
|
{
|
|
return ConvertToEntitySet(table);
|
|
}
|
|
}
|
|
|
|
public long Count()
|
|
{
|
|
object count = _dbProvider.ExecuteScalar(_countQuery);
|
|
if (null == count)
|
|
throw new InvalidOperationException(String.Format("Fault execute count query {0}", _countQuery));
|
|
return Convert.ToInt64(count);
|
|
}
|
|
|
|
public long Count<TField>(string fieldName, TField value)
|
|
{
|
|
if (null == value)
|
|
throw new ArgumentNullException(nameof(value));
|
|
if (string.IsNullOrWhiteSpace(fieldName))
|
|
throw new ArgumentNullException(nameof(fieldName));
|
|
var query = string.Format(_countByFieldNameQuery, fieldName, fieldName);
|
|
object count = _dbProvider.ExecuteScalar(query, new SqlParameter[]
|
|
{
|
|
new SqlParameter(fieldName, value)
|
|
});
|
|
if (null == count) throw new InvalidOperationException(String.Format("Fault execute count query {0}", _countQuery));
|
|
return Convert.ToInt64(count);
|
|
}
|
|
|
|
public bool Contains(T entity)
|
|
{
|
|
if (null == entity)
|
|
{
|
|
throw new ArgumentNullException(nameof(entity));
|
|
}
|
|
var count = _dbProvider.ExecuteScalar(_containsQuery, _mapper.CreateSqlDbParameters(entity));
|
|
if (null == count) throw new InvalidOperationException(String.Format("Fault execute query {0}", _containsQuery));
|
|
return Convert.ToInt64(count) > 0;
|
|
}
|
|
|
|
public bool ContainsId<TId>(TId id)
|
|
{
|
|
return Count<TId>(_mapper.IdentityName, id) > 0;
|
|
}
|
|
|
|
public bool Contains<TField>(string fieldName, TField value)
|
|
{
|
|
return Count<TField>(fieldName, value) > 0;
|
|
}
|
|
|
|
public void Update(T entity)
|
|
{
|
|
if (null == entity)
|
|
throw new ArgumentNullException(nameof(entity));
|
|
_dbProvider.ExecuteNonResult(_updateQuery, _mapper.CreateSqlDbParameters(entity));
|
|
}
|
|
|
|
public void Insert(T entity)
|
|
{
|
|
if (null == entity)
|
|
throw new ArgumentNullException(nameof(entity));
|
|
_dbProvider.ExecuteNonResult(_insertQuery, _mapper.CreateSqlDbParameters(entity));
|
|
}
|
|
|
|
public void Insert(IEnumerable<T> entities)
|
|
{
|
|
if (null == entities)
|
|
throw new ArgumentNullException(nameof(entities));
|
|
var commandList =
|
|
entities.
|
|
Select(e => new ZSqlCommand { Query = _insertQuery, Parameters = _mapper.CreateSqlDbParameters(e) });
|
|
_dbProvider.ExecuteNonResult(commandList);
|
|
}
|
|
|
|
public void Update(IEnumerable<T> entities)
|
|
{
|
|
if (null == entities)
|
|
throw new ArgumentNullException(nameof(entities));
|
|
var commandList =
|
|
entities.
|
|
Select(e => new ZSqlCommand { Query = _updateQuery, Parameters = _mapper.CreateSqlDbParameters(e) });
|
|
_dbProvider.ExecuteNonResult(commandList);
|
|
}
|
|
|
|
public void Remove(T entity)
|
|
{
|
|
if (null == entity)
|
|
throw new ArgumentNullException(nameof(entity));
|
|
_dbProvider.ExecuteNonResult(_removeByIdQuery, new SqlParameter[]
|
|
{
|
|
new SqlParameter(_mapper.IdentityName, _mapper.GetIdentity(entity))
|
|
});
|
|
}
|
|
|
|
public void RemoveById<TId>(TId id)
|
|
{
|
|
if (null == id)
|
|
throw new ArgumentNullException(nameof(id));
|
|
_dbProvider.ExecuteNonResult(_removeByIdQuery, new SqlParameter[]
|
|
{
|
|
new SqlParameter(_mapper.IdentityName, id)
|
|
});
|
|
}
|
|
|
|
public void Remove<TField>(string fieldName, TField value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(fieldName))
|
|
throw new ArgumentNullException(nameof(fieldName));
|
|
if (null == value)
|
|
throw new ArgumentNullException(nameof(value));
|
|
var query = string.Format(_removeByFieldQuery, fieldName, fieldName);
|
|
_dbProvider.ExecuteNonResult(query, new SqlParameter[]
|
|
{
|
|
new SqlParameter(fieldName, value)
|
|
});
|
|
}
|
|
#endregion
|
|
|
|
#region Specification queries
|
|
public T SingleOrDefault(ISpecification<T> specification)
|
|
{
|
|
if (null == specification)
|
|
throw new ArgumentNullException(nameof(specification));
|
|
ISqlServerSpecification sqlSpecification;
|
|
if (true == TryGetWhere(specification, out sqlSpecification))
|
|
{
|
|
string query = null;
|
|
var where = BuildWherePart(sqlSpecification);
|
|
if (false == string.IsNullOrWhiteSpace(where))
|
|
{
|
|
query = _getTopOneQuery + " WHERE " + where;
|
|
using (var table = _dbProvider.ExecuteQueryDataTable(query, sqlSpecification.Parameters))
|
|
{
|
|
if (null != table && table.Rows.Count > 0)
|
|
{
|
|
return _mapper.Deserialize(table.Rows[0]);
|
|
}
|
|
return default(T);
|
|
}
|
|
}
|
|
}
|
|
// No sql specification
|
|
T result = default(T);
|
|
_dbProvider.LazySelect(_getAllQuery, null, reader =>
|
|
{
|
|
var entity = _mapper.Deserialize(reader);
|
|
if (specification.IsSatisfiedBy(entity))
|
|
{
|
|
result = entity;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
public IEnumerable<T> Get(ISpecification<T> specification)
|
|
{
|
|
if (null == specification)
|
|
throw new ArgumentNullException(nameof(specification));
|
|
ISqlServerSpecification sqlSpecification;
|
|
if (true == TryGetWhere(specification, out sqlSpecification))
|
|
{
|
|
string query = null;
|
|
var where = BuildWherePart(sqlSpecification);
|
|
if (false == string.IsNullOrWhiteSpace(where))
|
|
{
|
|
query = _getAllQuery + " WHERE " + where;
|
|
using (var ds = _dbProvider.ExecuteQuerySqlDataSet(query, sqlSpecification.Parameters))
|
|
{
|
|
return ConvertToEntitySet(ds.Tables[0]);
|
|
}
|
|
}
|
|
}
|
|
// No sql specification
|
|
var result = new List<T>();
|
|
_dbProvider.LazySelect(_getAllQuery, null, reader =>
|
|
{
|
|
var entity = _mapper.Deserialize(reader);
|
|
if (specification.IsSatisfiedBy(entity))
|
|
{
|
|
result.Add(entity);
|
|
}
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
public bool Contains(ISpecification<T> specification)
|
|
{
|
|
if (null == specification)
|
|
throw new ArgumentNullException(nameof(specification));
|
|
ISqlServerSpecification sqlSpecification;
|
|
if (true == TryGetWhere(specification, out sqlSpecification))
|
|
{
|
|
var where = BuildWherePart(sqlSpecification);
|
|
if (false == string.IsNullOrWhiteSpace(where))
|
|
{
|
|
string query = String.Format("SELECT COUNT(*) FROM [{0}] WHERE {1}", _mapper.TableName, where);
|
|
object count = _dbProvider.ExecuteScalar(query, sqlSpecification.Parameters);
|
|
if (null == count) throw new InvalidOperationException(String.Format("Fault execute query {0}", query));
|
|
return Convert.ToInt64(count) > 0;
|
|
}
|
|
}
|
|
bool result = false;
|
|
_dbProvider.LazySelect(_getAllQuery, null, reader =>
|
|
{
|
|
var entity = _mapper.Deserialize(reader);
|
|
if (specification.IsSatisfiedBy(entity))
|
|
{
|
|
result = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
public long Count(ISpecification<T> specification)
|
|
{
|
|
if (null == specification)
|
|
throw new ArgumentNullException(nameof(specification));
|
|
ISqlServerSpecification sqlSpecification;
|
|
if (true == TryGetWhere(specification, out sqlSpecification))
|
|
{
|
|
var where = BuildWherePart(sqlSpecification);
|
|
object count = null;
|
|
if (false == string.IsNullOrWhiteSpace(where))
|
|
{
|
|
count = _dbProvider.ExecuteScalar(String.Format("{0} WHERE {1}", _countQuery, where), sqlSpecification.Parameters);
|
|
}
|
|
if (null == count) throw new InvalidOperationException("Fault execute query");
|
|
if (DBNull.Value == count) return 0;
|
|
return Convert.ToInt64(count);
|
|
}
|
|
long result = 0;
|
|
_dbProvider.LazySelect(_getAllQuery, null, reader =>
|
|
{
|
|
var entity = _mapper.Deserialize(reader);
|
|
if (specification.IsSatisfiedBy(entity))
|
|
{
|
|
result++;
|
|
}
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
public void Remove(ISpecification<T> specification)
|
|
{
|
|
if (null == specification)
|
|
throw new ArgumentNullException(nameof(specification));
|
|
ISqlServerSpecification sqlSpecification;
|
|
if (true == TryGetWhere(specification, out sqlSpecification))
|
|
{
|
|
var where = BuildWherePart(sqlSpecification);
|
|
if (false == string.IsNullOrWhiteSpace(where))
|
|
{
|
|
string query = string.Format("DELETE FROM [{0}] WHERE {1}", _mapper.TableName, where);
|
|
_dbProvider.ExecuteNonResult(query, sqlSpecification.Parameters);
|
|
return;
|
|
}
|
|
}
|
|
_dbProvider.LazySelect(_getAllQuery, null, reader =>
|
|
{
|
|
var entity = _mapper.Deserialize(reader);
|
|
if (specification.IsSatisfiedBy(entity))
|
|
{
|
|
Remove(entity);
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
#endregion
|
|
|
|
#region Helpers
|
|
private void VerifyDb()
|
|
{
|
|
if (false == _dbProvider.ExistsTable(_mapper.TableName))
|
|
{
|
|
_dbProvider.ExecuteNonResult(_mapper.GetCreateQuery());
|
|
}
|
|
_mapper.TraversalFields(f =>
|
|
{
|
|
if (f.IsIndexed)
|
|
{
|
|
var existsQuery = _mapper.GetIndexExistsQuery(f);
|
|
if ((int)_dbProvider.ExecuteScalar(existsQuery) == 0)
|
|
{
|
|
var createQuery = _mapper.GetCreateIndexQuery(f);
|
|
_dbProvider.ExecuteNonResult(createQuery);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private IEnumerable<T> ConvertToEntitySet(DataTable _dt)
|
|
{
|
|
var result = new List<T>();
|
|
_dt.Do(dt =>
|
|
{
|
|
foreach (DataRow row in dt.Rows)
|
|
{
|
|
try
|
|
{
|
|
result.Add(_mapper.Deserialize(row));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new InvalidCastException("Repository convert entity from db record to object fault", ex);
|
|
}
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
private bool TryGetWhere(ISpecification<T> originalSpecifiaction, out ISqlServerSpecification sqlSpecification)
|
|
{
|
|
sqlSpecification = (originalSpecifiaction as ISqlServerSpecification);
|
|
return sqlSpecification != null;
|
|
}
|
|
|
|
private string BuildWherePart(ISqlServerSpecification specification)
|
|
{
|
|
if (false == string.IsNullOrWhiteSpace(specification.Query))
|
|
return specification.Query;
|
|
else if (specification.Parameters != null)
|
|
return string.Join(" AND ", specification.Parameters.
|
|
Select(p => string.Format("[{0}] = @{1}", p.ParameterName, p.ParameterName)));
|
|
return null;
|
|
}
|
|
#endregion
|
|
|
|
#region Prebuild queries
|
|
private string _insertQuery;
|
|
private string _updateQuery;
|
|
|
|
private string _getTopOneQuery;
|
|
private string _getAllQuery;
|
|
private string _getByIdQuery;
|
|
private string _getByFieldNameQuery;
|
|
|
|
private string _countQuery;
|
|
private string _countByFieldNameQuery;
|
|
|
|
private string _containsQuery;
|
|
|
|
private string _removeByFieldQuery;
|
|
private string _removeByIdQuery;
|
|
|
|
private void Prebuilt()
|
|
{
|
|
_insertQuery = BuildInsertQuery();
|
|
_updateQuery = BuildUpdateQuery();
|
|
|
|
_getAllQuery = string.Format("SELECT * FROM [{0}]", _mapper.TableName);
|
|
_getTopOneQuery = string.Format("SELECT TOP (1) * FROM [{0}]", _mapper.TableName);
|
|
_getByIdQuery = string.Format("SELECT * FROM [{0}] WHERE {1}=@{2}",
|
|
_mapper.TableName, _mapper.IdentityName, _mapper.IdentityName);
|
|
_getByFieldNameQuery = _getAllQuery + " WHERE {0}=@{1}";
|
|
_countQuery = string.Format("SELECT COUNT(*) FROM [{0}]", _mapper.TableName);
|
|
_countByFieldNameQuery = _countQuery + " WHERE {0}=@{1}";
|
|
_containsQuery = BuildContainsQuery();
|
|
_removeByIdQuery = String.Format("DELETE FROM [{0}] WHERE [{1}] = @{2}",
|
|
_mapper.TableName, _mapper.IdentityName, _mapper.IdentityName);
|
|
_removeByFieldQuery = String.Format("DELETE FROM [{0}] WHERE ", _mapper.TableName) + " [{0}] = @{1}";
|
|
}
|
|
|
|
private string BuildContainsQuery()
|
|
{
|
|
var query = new StringBuilder(_countQuery);
|
|
query.Append(" WHERE ");
|
|
_mapper.TraversalFields(f =>
|
|
{
|
|
query.AppendFormat("[{0}] = @{1} AND ", f.Name, f.Name);
|
|
});
|
|
if (StringExtensions.EndsWith(query, "AND ")) query.Remove(query.Length - 4, 4);
|
|
if (StringExtensions.EndsWith(query, "WHERE ")) query.Remove(query.Length - 6, 6);
|
|
return query.ToString();
|
|
}
|
|
|
|
private string BuildInsertQuery()
|
|
{
|
|
var query = new StringBuilder();
|
|
query.AppendFormat("INSERT INTO [{0}](", _mapper.TableName);
|
|
var values = new StringBuilder(" VALUES(");
|
|
_mapper.TraversalFields(f =>
|
|
{
|
|
if (f.AutoIncrement == false)
|
|
{
|
|
query.Append("[" + f.Name + "],");
|
|
values.Append("@" + f.Name + ",");
|
|
}
|
|
});
|
|
query.Remove(query.Length - 1, 1);
|
|
query.Append(")");
|
|
query.AppendFormat(" OUTPUT INSERTED.{0} ", _mapper.IdentityName);
|
|
values.Remove(values.Length - 1, 1);
|
|
values.Append(")");
|
|
query.Append(values);
|
|
return query.ToString();
|
|
}
|
|
|
|
private string BuildUpdateQuery()
|
|
{
|
|
var query = new StringBuilder();
|
|
query.AppendFormat("UPDATE[{0}] SET ", _mapper.TableName);
|
|
_mapper.TraversalFields(f =>
|
|
{
|
|
if (f.IsIdentity == false && f.AutoIncrement == false)
|
|
query.Append("[" + f.Name + "] = @" + f.Name + ",");
|
|
});
|
|
query.Remove(query.Length - 1, 1);
|
|
query.AppendFormat(" OUTPUT INSERTED.{0} WHERE [{1}] = @{2}", _mapper.IdentityName, _mapper.IdentityName, _mapper.IdentityName);
|
|
return query.ToString();
|
|
}
|
|
#endregion
|
|
|
|
#region IDisposable
|
|
public void Dispose()
|
|
{
|
|
}
|
|
#endregion
|
|
|
|
public void Execute(string query)
|
|
{
|
|
_dbProvider.ExecuteNonResult(query);
|
|
}
|
|
}
|
|
}
|