pull/1/head
a.bozhenov 6 years ago
parent 13cb6c6b0e
commit bb34148ae0

@ -0,0 +1,187 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;
namespace ZeroLevel.SqlServer
{
public abstract class BaseSqlDbMapper
{
protected abstract IDbMapper Mapper { get; }
protected readonly string _tableName;
public string TableName { get { return _tableName; } }
protected BaseSqlDbMapper(string tableName)
{
_tableName = tableName;
}
public object GetIdentity(object entity)
{
if (Mapper.IdentityField != null)
return Mapper.IdentityField.Getter(entity);
return null;
}
public string IdentityName
{
get
{
return Mapper.IdentityField?.Name;
}
}
#region QUERIES
#region INDEXES
public string GetIndexExistsQuery(IDbField field)
{
if (field.IsIndexed)
{
return string.Format(
"SELECT COUNT(*) FROM sys.indexes WHERE name = 'idx_{0}_{1}' AND object_id = OBJECT_ID('{2}')",
_tableName, field.Name, _tableName);
}
return null;
}
public string GetCreateIndexQuery(IDbField field)
{
if (field.IsIndexed)
{
return string.Format("CREATE INDEX idx_{0}_{1} ON [{2}]({3});", _tableName, field.Name, _tableName, field.Name);
}
return null;
}
#endregion
#region CREATE
public static HashSet<DbType> FieldsHasSize = new HashSet<DbType>
{
DbType.String, DbType.Decimal, DbType.AnsiString, DbType.AnsiStringFixedLength,
DbType.StringFixedLength, DbType.VarNumeric
};
private string _createString = null;
private readonly object _createStringBuildLocker = new object();
public string GetCreateQuery(bool rebuild = false)
{
lock (_createStringBuildLocker)
{
if (_createString == null || rebuild)
{
StringBuilder create = new StringBuilder("CREATE TABLE [" + _tableName + "]");
create.Append("(");
Mapper.TraversalFields(f =>
{
var sqlType = DbTypeMapper.ToSqlDbType(f.ClrType);
create.Append("[" + f.Name + "] " + sqlType);
if (FieldsHasSize.Contains(f.DbType) && f.Size != 0)
{
if (f.DbType == DbType.Decimal)
{
int p = 19, s = 4;
if (f.Size > 0)
{
p = (int)f.Size;
if (s >= p)
{
if (p <= 2) s = 0;
else s = p - 1;
}
}
create.AppendFormat("({0},{1})", p, s);
}
else
{
create.AppendFormat("({0})", ((f.Size == -1) ? "max" : f.Size.ToString()));
}
}
if (f.IsIdentity)
{
create.Append(" PRIMARY KEY");
}
if (f.AllowNull)
{
create.Append(" NULL");
}
else
{
create.Append(" NOT NULL");
}
if (f.AutoIncrement)
{
create.Append(" IDENTITY (0, 1)");
}
create.Append(",");
});
_createString = create.ToString().TrimEnd(',') + ")";
}
}
return _createString;
}
#endregion
#endregion
public SqlParameter[] CreateSqlDbParameters(object entity)
{
if (entity.GetType() != Mapper.EntityType)
throw new InvalidCastException("Entity type is different from serializer entity type");
var list = new List<SqlParameter>();
Mapper.TraversalFields(field =>
{
var par = new SqlParameter();
par.Value = ValueToSqlServerObject(field.Getter(entity), field.ClrType);
// ADO.NET bug
// https://connect.microsoft.com/VisualStudio/feedback/details/381934/sqlparameter-dbtype-dbtype-time-sets-the-parameter-to-sqldbtype-datetime-instead-of-sqldbtype-time
if (field.DbType == DbType.Time)
{
par.SqlDbType = SqlDbType.Time;
}
else
{
par.DbType = field.DbType; // Если задать в конструкторе, то тип может переопределиться при задании значения
}
par.ParameterName = field.Name;
list.Add(par);
});
return list.ToArray();
}
#region Datetime helper
private static DateTime MinSqlDbDateTimeValue = new DateTime(1753, 01, 01);
protected object ValueToSqlServerObject(object obj, Type type)
{
if (type == typeof(DateTime))
{
return DateTimeToSqlDbValue((DateTime)obj);
}
return obj ?? DBNull.Value;
}
/// <summary>
/// Подготовка даты к записи в SQLServer
/// (минимальные значения даты в .NET и SQL Server отличаются)
/// </summary>
protected object DateTimeToSqlDbValue(DateTime dt)
{
if (DateTime.Compare(dt, MinSqlDbDateTimeValue) <= 0)
return DBNull.Value;
return dt;
}
/// <summary>
/// Конвертер из элементов строки DataTable в DonNet тип
/// </summary>
/// <typeparam name="Tout">Тип на выходе</typeparam>
/// <param name="value">Значение из БД</param>
/// <returns>Результат</returns>
protected Tout Convert<Tout>(object value)
{
if (null == value || DBNull.Value == value)
return default(Tout);
return (Tout)System.Convert.ChangeType(value, typeof(Tout));
}
#endregion
}
}

@ -0,0 +1,72 @@
using System;
using System.Runtime.Serialization;
namespace ZeroLevel.SqlServer
{
[DataContract]
[Serializable]
public abstract class BaseEntity : IEntity
{
#region Properties
[DataMember]
[DbMember(false, true, false)]
public Guid Id
{
get;
set;
}
#endregion
#region Ctors
protected BaseEntity()
{
Id = Guid.NewGuid();
}
protected BaseEntity(Guid id)
{
if (id == Guid.Empty)
throw new ArgumentException("Entity id must not be empty");
Id = id;
}
protected BaseEntity(BaseEntity other)
{
if (other == null)
throw new ArgumentNullException(nameof(other));
Id = other.Id;
}
#endregion
public abstract object Clone();
#region Equal
public bool Equals(BaseEntity other)
{
if (this == null) // и так бывает
throw new NullReferenceException();
if (other == null)
return false;
if (ReferenceEquals(this, other))
return true;
if (this.GetType() != other.GetType())
return false;
return Id == other.Id;
}
public override bool Equals(object obj)
{
if (this == null)
throw new NullReferenceException();
return Equals(obj as BaseEntity);
}
public static bool operator ==(BaseEntity first, BaseEntity second) => Equals(first, second);
public static bool operator !=(BaseEntity first, BaseEntity second) => !Equals(first, second);
#endregion
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
}

@ -0,0 +1,55 @@
using System;
using System.Runtime.Serialization;
namespace ZeroLevel.SqlServer
{
[DataContract]
[Serializable]
public abstract class BaseVersionedEntity : BaseEntity, IVersionedEntity
{
#region Properties
[DataMember]
[DbMember(false)]
public long Version
{
get;
internal set;
}
#endregion
#region Ctors
protected BaseVersionedEntity()
: base()
{
}
// Конструктор protected BaseVersionedEntity(Guid id) исключен, т.к. без версии нет смысла создавать обхект с известным ID
protected BaseVersionedEntity(Guid id, long version)
: base(id)
{
Version = version;
}
protected BaseVersionedEntity(BaseVersionedEntity other)
: base(other)
{
Version = other.Version;
}
#endregion
public bool Equals(BaseVersionedEntity other)
{
if (base.Equals(other) == false) return false;
return Version == other.Version;
}
public override bool Equals(object obj)
{
return Equals(obj as BaseVersionedEntity);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}

@ -0,0 +1,9 @@
using System;
namespace ZeroLevel.SqlServer
{
public class DbIndexAttribute : Attribute
{
public DbIndexAttribute() { }
}
}

@ -0,0 +1,39 @@
using System;
namespace ZeroLevel.SqlServer
{
public class DbMemberAttribute : Attribute
{
#region Properties
public bool AllowNull { get; }
public bool AutoIncrement { get; }
public bool IsIdentity { get; }
public long Size { get; }
#endregion
#region Ctors
public DbMemberAttribute(bool allowNull)
: this(allowNull, -1, false, false) { }
public DbMemberAttribute(bool allowNull, long size)
: this(allowNull, size, false, false) { }
public DbMemberAttribute(bool allowNull, bool isIdentity)
: this(allowNull, -1, isIdentity, false) { }
public DbMemberAttribute(bool allowNull, bool isIdentity, bool autoIncrement)
: this(allowNull, -1, isIdentity, autoIncrement) { }
public DbMemberAttribute(bool allowNull, long size, bool isIdentity)
: this(allowNull, size, isIdentity, false) { }
public DbMemberAttribute(bool allowNull, long size, bool isIdentity, bool autoIncrement)
{
AllowNull = allowNull;
AutoIncrement = autoIncrement;
IsIdentity = isIdentity;
Size = size;
}
#endregion
}
}

@ -0,0 +1,16 @@
using System.Data;
using ZeroLevel.Services.ObjectMapping;
namespace ZeroLevel.SqlServer
{
public interface IDbField:
IMemberInfo
{
bool AutoIncrement { get; }
bool IsIdentity { get; }
bool IsIndexed { get; }
bool AllowNull { get; }
long Size { get; }
DbType DbType { get; }
}
}

@ -0,0 +1,29 @@
using System;
using System.Data;
using System.Data.Common;
namespace ZeroLevel.SqlServer
{
public interface IDbMapper
{
IDbField this[string name] { get; }
IDbField IdentityField { get; }
Type EntityType { get; }
object Id(object entity);
void TraversalFields(Action<IDbField> callback);
void TraversalFields(Func<IDbField, bool> callback);
void SetTypeConverter(Func<IDbField, object, object> converter);
bool Exists(string name);
#region Serialization
object Deserialize(DataRow row);
object Deserialize(DbDataReader reader);
#endregion
}
public interface IDbMapper<T> : IDbMapper
{
new T Deserialize(DataRow row);
new T Deserialize(DbDataReader reader);
}
}

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
namespace ZeroLevel.SqlServer
{
public interface IDbProvider
{
bool ExistsTable(string tableName);
DataTable ExecuteQueryDataTable(string query);
DataTable ExecuteQueryDataTable(string query, DbParameter[] par);
DataSet ExecuteQuerySqlDataSet(string query);
DataSet ExecuteQuerySqlDataSet(string query, DbParameter[] par);
object ExecuteScalar(string query);
object ExecuteScalar(string query, DbParameter[] par);
void ExecuteNonResult(IEnumerable<ZSqlCommand> commands);
int ExecuteNonResult(string query);
int ExecuteNonResult(string query, DbParameter[] par);
void LazySelect(string query, DbParameter[] par, Func<DbDataReader, bool> readHandler);
}
}

@ -0,0 +1,14 @@
using System;
namespace ZeroLevel.SqlServer
{
public interface IEntity : ICloneable
{
Guid Id { get; }
}
public interface IEntity<TKey> : ICloneable
{
TKey Id { get; }
}
}

@ -0,0 +1,7 @@
namespace ZeroLevel.SqlServer
{
public interface IVersionedEntity : IEntity
{
long Version { get; }
}
}

@ -0,0 +1,10 @@
using System.Data.Common;
namespace ZeroLevel.SqlServer
{
public class ZSqlCommand
{
public string Query;
public DbParameter[] Parameters;
}
}

@ -0,0 +1,50 @@
using System;
using System.Runtime.Serialization;
using ZeroLevel.Specification;
namespace ZeroLevel.SqlServer
{
[DataContract]
[Serializable]
public class IdentitySpecification<T> : BaseSpecification<T>
where T : IEntity
{
[DataMember]
protected Guid _id;
public IdentitySpecification(Guid id)
{
_id = id;
}
public override bool IsSatisfiedBy(T o)
{
return o.Id == _id;
}
public static ISpecification<T> Create(Guid id) { return new IdentitySpecification<T>(id); }
public static ISpecification<T> Create(IEntity entity) { return new IdentitySpecification<T>(entity.Id); }
}
[DataContract]
[Serializable]
public class IdentitySpecification<T, TKey> : BaseSpecification<T>
{
[DataMember]
private TKey _id;
private readonly IDbMapper<T> _mapper;
public IdentitySpecification(TKey id, bool poco)
{
_id = id;
_mapper = DbMapperFactory.Create<T>(poco);
}
public override bool IsSatisfiedBy(T o)
{
return _mapper.Id(o).Equals(_id);
}
public static ISpecification<T> Create(TKey id, bool poco) { return new IdentitySpecification<T, TKey>(id, poco); }
}
}

@ -0,0 +1,37 @@
using System;
using System.Data.SqlClient;
using ZeroLevel.SqlServer;
using ZeroLevel.Specification;
namespace ZeroLevel.SqlServer
{
public class SqlIdentitySpecification<T> : IdentitySpecification<T>, ISqlServerSpecification
where T : IEntity
{
public SqlIdentitySpecification(Guid id) : base(id)
{
}
public SqlParameter[] Parameters
{
get
{
return new SqlParameter[]
{
new SqlParameter(DbMapperFactory.Create<T>().IdentityField.Name, _id)
};
}
}
public string Query
{
get
{
return string.Empty;
}
}
public static ISpecification<Te> Create<Te>(Guid id) where Te: IEntity
{ return new SqlIdentitySpecification<Te>(id); }
}
}

@ -0,0 +1,96 @@
using System;
using System.Data;
using System.Reflection;
using ZeroLevel.Services.ObjectMapping;
using ZeroLevel.Services.Reflection;
namespace ZeroLevel.SqlServer
{
public class DbField : MapMemberInfo, IDbField
{
public bool AutoIncrement { get; internal set; }
public bool IsIdentity { get; internal set; }
public bool IsIndexed { get; internal set; }
public bool AllowNull { get; internal set; }
public long Size { get; internal set; }
public DbType DbType { get; internal set; }
private DbField(Action<object, object> setter, Func<object, object> getter)
:base(setter, getter)
{
}
private static bool IsNullable(Type type)
{
if (!type.IsValueType) return true; // ref-type
if (Nullable.GetUnderlyingType(type) != null) return true; // Nullable<T>
return false; // value-type
}
public static DbField FromField(FieldInfo fieldInfo)
{
var meta = ((DbMemberAttribute)Attribute.GetCustomAttribute(fieldInfo, typeof(DbMemberAttribute)));
var index = ((DbIndexAttribute)Attribute.GetCustomAttribute(fieldInfo, typeof(DbIndexAttribute)));
var field = new DbField(TypeGetterSetterBuilder.BuildSetter(fieldInfo), TypeGetterSetterBuilder.BuildGetter(fieldInfo))
{
Name = fieldInfo.Name,
IsIdentity = meta?.IsIdentity ?? false,
AllowNull = meta?.AllowNull ?? true,
AutoIncrement = meta?.AutoIncrement ?? false,
Size = meta?.Size ?? -1,
IsIndexed = index != null
};
field.IsField = true;
var type = fieldInfo.FieldType;
field.ClrType = type;
field.DbType = type.ToDbType();
return field;
}
public static DbField FromProperty(PropertyInfo propertyInfo)
{
var meta = ((DbMemberAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(DbMemberAttribute)));
var index = ((DbIndexAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(DbIndexAttribute)));
var field = new DbField(TypeGetterSetterBuilder.BuildSetter(propertyInfo), TypeGetterSetterBuilder.BuildGetter(propertyInfo))
{
Name = propertyInfo.Name,
IsIdentity = meta?.IsIdentity ?? false,
AllowNull = meta?.AllowNull ?? true,
AutoIncrement = meta?.AutoIncrement ?? false,
Size = meta?.Size ?? -1,
IsIndexed = index != null
};
field.IsField = false;
var type = propertyInfo.PropertyType;
field.ClrType = type;
field.DbType = type.ToDbType();
return field;
}
public new static DbField FromMember(MemberInfo memberInfo)
{
switch (memberInfo.MemberType)
{
case MemberTypes.Field:
return FromField(memberInfo as FieldInfo);
case MemberTypes.Property:
return FromProperty(memberInfo as PropertyInfo);
}
return null;
}
public void SetValue(object instance, object dbvalue, Func<DbField, object, object> converter = null)
{
var value = (null == dbvalue || DBNull.Value == dbvalue) ? null : dbvalue;
if (null != converter)
{
value = converter(this, value);
}
if (null == value && false == IsNullable(ClrType))
Setter(instance, TypeExtensions.GetDefault(ClrType));
else
Setter(instance, value);
}
}
}

@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Reflection;
namespace ZeroLevel.SqlServer
{
public class DbMapper: IDbMapper
{
protected readonly Dictionary<string, DbField> _fields = new Dictionary<string, DbField>();
private string _identityFieldName;
private readonly Type _entityType;
/// <summary>
/// В случае задания в true, все поля класса считаются данными модели, в т.ч. не отвеченные аттрибутом DbMember
/// </summary>
private readonly bool _analizeAsPoco;
protected Func<DbField, object, object> typeConverter;
public void SetTypeConverter(Func<IDbField, object, object> converter)
{
typeConverter = converter;
}
public IDbField IdentityField
{
get
{
if (false == string.IsNullOrWhiteSpace(_identityFieldName))
{
return _fields[_identityFieldName];
}
return null;
}
}
public Type EntityType
{
get
{
return _entityType;
}
}
public IDbField this[string name]
{
get
{
return _fields[name];
}
}
public object Id(object entity)
{
return IdentityField?.Getter(entity);
}
internal DbMapper(Type entityType, bool as_poco)
{
_analizeAsPoco = as_poco;
_entityType = entityType;
BuildMapping();
}
private void BuildMapping()
{
_entityType.GetMembers(
BindingFlags.Public |
BindingFlags.FlattenHierarchy |
BindingFlags.GetField |
BindingFlags.GetProperty |
BindingFlags.Instance).
Do(members =>
{
IEnumerable<MemberInfo> memberList;
if (false == _analizeAsPoco)
{
memberList = members.Where(m => null != Attribute.GetCustomAttribute(m, typeof(DbMemberAttribute)));
}
else
{
memberList = members;
}
foreach (var member in memberList)
{
if (member.MemberType != MemberTypes.Field && member.MemberType != MemberTypes.Property)
continue;
var field = DbField.FromMember(member);
if (field.IsIdentity)
{
_identityFieldName = member.Name;
}
_fields.Add(field.Name, field);
}
if (true == string.IsNullOrWhiteSpace(_identityFieldName))
{
_identityFieldName = _fields.Keys.FirstOrDefault(f => f.Equals("id", StringComparison.OrdinalIgnoreCase));
if (true == string.IsNullOrWhiteSpace(_identityFieldName))
{
_identityFieldName = _fields.Keys.FirstOrDefault(f =>
f.IndexOf("id", StringComparison.OrdinalIgnoreCase) >= 0 &&
f.IndexOf(_entityType.Name, StringComparison.OrdinalIgnoreCase) >= 0);
}
}
if (false == string.IsNullOrWhiteSpace(_identityFieldName))
{
_fields[_identityFieldName].IsIdentity = true;
_fields[_identityFieldName].AllowNull = false;
}
});
}
public void TraversalFields(Action<IDbField> callback)
{
foreach (var f in _fields) callback(f.Value);
}
public void TraversalFields(Func<IDbField, bool> callback)
{
foreach (var f in _fields) if (false == callback(f.Value)) return;
}
public bool Exists(string name)
{
return _fields.ContainsKey(name);
}
#region Serialization
public object Deserialize(DataRow row)
{
if (null == row) throw new ArgumentNullException(nameof(row));
var result = Activator.CreateInstance(_entityType);
foreach (var field in _fields)
{
var value = (null == row[field.Key] || DBNull.Value == row[field.Key]) ? null : row[field.Key];
if (null != typeConverter)
{
field.Value.Setter(result, typeConverter(field.Value, value));
}
else
{
field.Value.Setter(result, value);
}
}
return result;
}
public object Deserialize(DbDataReader reader)
{
if (null == reader) throw new ArgumentNullException(nameof(reader));
var result = Activator.CreateInstance(_entityType);
foreach (var field in _fields)
{
var value = (null == reader[field.Key] || DBNull.Value == reader[field.Key]) ? null : reader[field.Key];
if (null != typeConverter)
{
field.Value.Setter(result, typeConverter(field.Value, value));
}
else
{
field.Value.Setter(result, value);
}
}
return result;
}
#endregion
}
}

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
namespace ZeroLevel.SqlServer
{
public static class DbMapperFactory
{
private static readonly Dictionary<Type, IDbMapper> _mapperPool = new Dictionary<Type, IDbMapper>();
private static readonly object _poolLocker = new object();
/// <summary>
/// Создание маппера
/// </summary>
/// <param name="entityType">Тип представляющий модель данных</param>
/// <param name="asPoco">В случае задания в true, все поля класса считаются данными модели, в т.ч. не отвеченные аттрибутом DbMember</param>
/// <returns>Маппер</returns>
public static IDbMapper Create(Type entityType, bool asPoco = false)
{
if (null == entityType)
throw new ArgumentNullException(nameof(entityType));
lock (_poolLocker)
{
if (false == _mapperPool.ContainsKey(entityType))
{
var gt = typeof(IDbMapper<>);
var rt = gt.MakeGenericType(new Type[] { entityType });
_mapperPool.Add(entityType, new DbMapper(rt, asPoco));
}
}
return _mapperPool[entityType];
}
/// <summary>
/// Создание маппера
/// </summary>
/// <param name="asPoco">В случае задания в true, все поля класса считаются данными модели, в т.ч. не отвеченные аттрибутом DbMember</param>
/// <returns>Маппер</returns>
public static IDbMapper<T> Create<T>(bool asPoco = false)
{
var entityType = typeof(T);
lock (_poolLocker)
{
if (false == _mapperPool.ContainsKey(entityType))
{
_mapperPool.Add(entityType, new DbMapper<T>(asPoco));
}
}
return (IDbMapper<T>)_mapperPool[entityType];
}
}
}

@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
namespace ZeroLevel.SqlServer
{
public static class DbTypeMapper
{
static Dictionary<Type, DbType> typeMap;
static DbTypeMapper()
{
typeMap = new Dictionary<Type, DbType>
{
[typeof(byte)] = DbType.Byte,
[typeof(sbyte)] = DbType.SByte,
[typeof(short)] = DbType.Int16,
[typeof(ushort)] = DbType.UInt16,
[typeof(int)] = DbType.Int32,
[typeof(uint)] = DbType.UInt32,
[typeof(long)] = DbType.Int64,
[typeof(ulong)] = DbType.UInt64,
[typeof(float)] = DbType.Single,
[typeof(double)] = DbType.Double,
[typeof(decimal)] = DbType.Decimal,
[typeof(bool)] = DbType.Boolean,
[typeof(string)] = DbType.String,
[typeof(char)] = DbType.StringFixedLength,
[typeof(Guid)] = DbType.Guid,
[typeof(DateTime)] = DbType.DateTime,
[typeof(DateTimeOffset)] = DbType.DateTimeOffset,
[typeof(TimeSpan)] = DbType.Time,
[typeof(byte[])] = DbType.Binary,
[typeof(byte?)] = DbType.Byte,
[typeof(sbyte?)] = DbType.SByte,
[typeof(short?)] = DbType.Int16,
[typeof(ushort?)] = DbType.UInt16,
[typeof(int?)] = DbType.Int32,
[typeof(uint?)] = DbType.UInt32,
[typeof(long?)] = DbType.Int64,
[typeof(ulong?)] = DbType.UInt64,
[typeof(float?)] = DbType.Single,
[typeof(double?)] = DbType.Double,
[typeof(decimal?)] = DbType.Decimal,
[typeof(bool?)] = DbType.Boolean,
[typeof(char?)] = DbType.StringFixedLength,
[typeof(Guid?)] = DbType.Guid,
[typeof(DateTime?)] = DbType.DateTime,
[typeof(DateTimeOffset?)] = DbType.DateTimeOffset,
[typeof(TimeSpan?)] = DbType.Time,
[typeof(object)] = DbType.Object
};
}
/// <summary>
/// Для value типов помеченных как Nullable вытаскивает оригинальный value тип
/// Не value и не nullable типы не преобразуются
/// </summary>
private static Type GetNonNullableType(Type t)
{
if (t.IsValueType)
{
// Detect Nullable<T>
if (Nullable.GetUnderlyingType(t) != null)
{
return t.GenericTypeArguments.Length > 0 ? t.GenericTypeArguments[0] : t;
}
}
return t;
}
public static DbType ToDbType(this Type type)
{
DbType dbType;
var theType = GetNonNullableType(type);
if (theType.IsEnum && !typeMap.ContainsKey(type))
{
theType = Enum.GetUnderlyingType(theType);
}
if (typeMap.TryGetValue(theType, out dbType))
{
return dbType;
}
return DbType.Object;
}
public static SqlDbType ToSqlDbType(this Type testType)
{
var theType = GetNonNullableType(testType);
if (theType.IsEnum)
{
return Enum.GetUnderlyingType(theType).ToSqlDbType();
}
if (theType == typeof(Byte[]) || theType == typeof(byte[])) return SqlDbType.Image;
if (theType == typeof(UInt16) || theType == typeof(ushort)) return SqlDbType.Int;
if (theType == typeof(UInt32) || theType == typeof(uint)) return SqlDbType.BigInt;
if (theType == typeof(UInt64) || theType == typeof(ulong)) return SqlDbType.Decimal;
if (theType == typeof(TimeSpan)) return SqlDbType.Time;
return new SqlParameter() { DbType = (DbType)Enum.Parse(typeof(DbType), theType.Name) }.SqlDbType;
}
public static Type ToClrType(string sqlType)
{
switch (sqlType.Trim().ToLowerInvariant())
{
case "bigint":
return typeof(long);
case "binary":
case "image":
case "timestamp":
case "varbinary":
return typeof(byte[]);
case "bit":
return typeof(bool);
case "char":
case "nchar":
case "ntext":
case "nvarchar":
case "text":
case "varchar":
case "xml":
return typeof(string);
case "datetime":
case "smalldatetime":
case "date":
case "datetime2":
return typeof(DateTime);
case "time":
return typeof(TimeSpan);
case "decimal":
case "money":
case "smallmoney":
return typeof(decimal);
case "float":
return typeof(double);
case "int":
return typeof(int);
case "real":
return typeof(float);
case "uniqueidentifier":
return typeof(Guid);
case "smallint":
return typeof(short);
case "tinyint":
return typeof(byte);
case "variant":
case "udt":
return typeof(object);
case "structured":
return typeof(DataTable);
case "datetimeoffset":
return typeof(DateTimeOffset);
default:
throw new ArgumentOutOfRangeException(sqlType);
}
}
}
}

@ -0,0 +1,35 @@
using System;
using System.Data;
using System.Data.Common;
namespace ZeroLevel.SqlServer
{
public class DbMapper<T> : DbMapper, IDbMapper<T>
{
public DbMapper(bool as_poco) : base(typeof(T), as_poco)
{
}
public new T Deserialize(DataRow row)
{
if (null == row) throw new ArgumentNullException(nameof(row));
var result = Activator.CreateInstance<T>();
foreach (var field in _fields)
{
field.Value.SetValue(result, row[field.Key], typeConverter);
}
return result;
}
public new T Deserialize(DbDataReader reader)
{
if (null == reader) throw new ArgumentNullException(nameof(reader));
var result = Activator.CreateInstance<T>();
foreach (var field in _fields)
{
field.Value.SetValue(result, reader[field.Key], typeConverter);
}
return result;
}
}
}

@ -0,0 +1,47 @@
using System;
using System.Data;
using System.Data.Common;
namespace ZeroLevel.SqlServer
{
public class SqlDbMapper<T> : BaseSqlDbMapper
{
protected readonly IDbMapper<T> _mapper;
protected override IDbMapper Mapper
{
get
{
return _mapper;
}
}
public IDbField IdentityField
{
get
{
return _mapper.IdentityField;
}
}
public SqlDbMapper(bool entity_is_poco) : base(typeof(T).Name)
{
_mapper = DbMapperFactory.Create<T>(entity_is_poco);
}
public T Deserialize(DataRow row)
{
return _mapper.Deserialize(row);
}
public T Deserialize(DbDataReader reader)
{
return _mapper.Deserialize(reader);
}
public void TraversalFields(Action<IDbField> callback)
{
_mapper.TraversalFields(callback);
}
}
}

@ -0,0 +1,10 @@
using System.Data.SqlClient;
namespace ZeroLevel.SqlServer
{
public interface ISqlServerSpecification
{
string Query { get; }
SqlParameter[] Parameters { get; }
}
}

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ZeroLevel.SqlServer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ZeroLevel.SqlServer")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a8ad956f-1559-45ec-a7db-42290494e2c5")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -0,0 +1,106 @@
using System;
using System.Data.SqlClient;
using System.Globalization;
using System.Security.Permissions;
namespace ZeroLevel.SqlServer
{
public sealed class SqlDbConnectionFactory
{
public string ConnectionString
{
get { return dbConnectionString.ConnectionString; }
}
public string Server
{
get { return dbConnectionString.DataSource; }
}
public string Base
{
get { return dbConnectionString.InitialCatalog; }
}
#region Поля
private SqlConnectionStringBuilder dbConnectionString;
/// <summary>
/// Текущая строка подключения
/// </summary>
private readonly string _currentConnectionString = String.Empty;
#endregion
public SqlDbConnectionFactory(SqlConnectionStringBuilder builder)
{
_currentConnectionString = builder.ConnectionString;
Initialize();
}
public SqlDbConnectionFactory(string connectionString)
{
_currentConnectionString = connectionString;
Initialize();
}
public SqlDbConnectionFactory(string server, string database, string login, string password)
{
_currentConnectionString = BuildConnectionString(server, database, login, password);
Initialize();
}
private void Initialize()
{
try
{
var perm = new SqlClientPermission(PermissionState.Unrestricted);
perm.Demand();
perm = null;
}
catch
{
throw new ApplicationException("No permission for access to SqlClient");
}
dbConnectionString = new SqlConnectionStringBuilder(_currentConnectionString);
dbConnectionString.Pooling = true;
dbConnectionString.MaxPoolSize = 50;
}
public SqlConnection CreateConnection()
{
var connection = new SqlConnection(ConnectionString);
connection.Open();
return connection;
}
#region Helpers
#region Строки подключения
/// <summary>
/// Стандартное подключение
/// </summary>
private const string StandartConnectionString = "Server={0};Database={1};User ID={2};Password=\"{3}\";";
/// <summary>
/// Доверенное подключение
/// </summary>
private const string TrustedConnectionString = "Data Source={0};Initial Catalog={1};Integrated Security=SSPI;";
#endregion
internal static string BuildConnectionString(string server, string dataBase, string user, string pwd)
{
if (String.IsNullOrEmpty(user) || String.IsNullOrEmpty(pwd))
{
return String.Format(CultureInfo.CurrentCulture, TrustedConnectionString, server, dataBase);
}
else
{
return String.Format(CultureInfo.CurrentCulture, StandartConnectionString, server, dataBase, user, pwd);
}
}
#endregion
public override int GetHashCode()
{
return this.ConnectionString.GetHashCode();
}
}
}

@ -0,0 +1,203 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
namespace ZeroLevel.SqlServer
{
public sealed class SqlDbInfo
{
#region Ctor
public SqlDbInfo(SqlDbProvider provider)
{
_provider = provider;
}
#endregion
private static string FixTableName(string tableName)
{
return tableName.Trim().ToLower();
}
public void CollectDatabaseInfo(bool tables, bool views, bool storedProcedures)
{
if (tables)
CollectTableInformation();
}
public SqlDbTableInfo this[string tableName]
{
get
{
tableName = FixTableName(tableName);
if (_tables.ContainsKey(tableName))
{
return _tables[tableName];
}
throw new KeyNotFoundException("Таблица " + tableName + " отсутствует в базе " + _provider.Server + "\\" + _provider.Base);
}
}
#region Private Fields
private readonly SqlDbProvider _provider;
private readonly Dictionary<string, SqlDbTableInfo> _tables = new Dictionary<string, SqlDbTableInfo>();
private readonly List<SqlDbForeignKeyInfo> _foreignKeys = new List<SqlDbForeignKeyInfo>();
private readonly List<SqlDbPrimaryKeyInfo> _primaryKeys = new List<SqlDbPrimaryKeyInfo>();
private readonly List<SqlDbObjectInfo> _storedProcedures = new List<SqlDbObjectInfo>();
private readonly List<SqlDbObjectInfo> _views = new List<SqlDbObjectInfo>();
#endregion
#region Public database info
public IEnumerable<string> Tables
{
get
{
return _tables.Keys;
}
}
public IEnumerable<SqlDbTableInfo> TablesInfo
{
get
{
return _tables.Values;
}
}
public IEnumerable<SqlDbPrimaryKeyInfo> PrimaryKeys
{
get
{
return _primaryKeys;
}
}
public IEnumerable<SqlDbForeignKeyInfo> ForeignKeys
{
get
{
return _foreignKeys;
}
}
public IEnumerable<SqlDbObjectInfo> StoredProcedures
{
get
{
return _storedProcedures;
}
}
public IEnumerable<SqlDbObjectInfo> Views
{
get
{
return _views;
}
}
#endregion
#region Public methods
public bool ContainTable(string tableName)
{
tableName = FixTableName(tableName);
return _tables.ContainsKey(tableName);
}
public bool ContainPrimaryKey(SqlDbPrimaryKeyInfo pk)
{
return _primaryKeys.Contains(pk);
}
public bool ContainForeignKey(SqlDbForeignKeyInfo fk)
{
return _foreignKeys.Contains(fk);
}
public SqlDbTableInfo TableInfo(string tableName)
{
tableName = FixTableName(tableName);
if (ContainTable(tableName))
{
return _tables[tableName];
}
return null;
}
#endregion
#region Helpers
/// <summary>
/// Сбор информации о таблицах, перчиных и внешних ключах
/// </summary>
private void CollectTableInformation()
{
// Таблицы
foreach (string table in GetTables())
{
SqlDbTableInfo info = GetTableInfo(table);
if (info != null)
{
string tableName = FixTableName(info.Name);
_tables.Add(tableName, info);
if (info.PrimaryKey != null)
{
_primaryKeys.Add(new SqlDbPrimaryKeyInfo { PrimaryKeyTable = tableName, PrimaryKeyColumn = info.PrimaryKey.Name });
}
}
}
// Внешние ключи
DataSet fkSet = _provider.ExecuteQuerySqlDataSet(SqlDbForeignKeyInfo.ForeignKeySelectQuery);
if (fkSet != null && fkSet.Tables.Count > 0)
{
foreach (DataRow row in fkSet.Tables[0].Rows)
{
_foreignKeys.Add(new SqlDbForeignKeyInfo
{
ForeignKeyName = Convert.ToString(row["Constraint_Name"], CultureInfo.CurrentCulture),
ForeignKeyTable = FixTableName(Convert.ToString(row["K_Table"], CultureInfo.CurrentCulture)),
ForeignKeyColumn = Convert.ToString(row["FK_Column"], CultureInfo.CurrentCulture),
PrimaryKeyTable = FixTableName(Convert.ToString(row["PK_Table"], CultureInfo.CurrentCulture)),
PrimaryKeyColumn = Convert.ToString(row["PK_Column"], CultureInfo.CurrentCulture)
});
}
}
}
#region Private
/// <summary>
/// Получение списка таблиц из базы данных
/// </summary>
private List<string> GetTables()
{
var tables = new List<string>();
using (DataSet ds = _provider.ExecuteQuerySqlDataSet("exec sp_tables"))
{
if (ds != null && ds.Tables.Count > 0)
{
foreach (DataRow row in ds.Tables[0].Rows)
{
if (String.Equals(row.ItemArray[3].ToString(), "TABLE", StringComparison.OrdinalIgnoreCase) &&
(false == String.Equals(row.ItemArray[1].ToString(), "sys", StringComparison.OrdinalIgnoreCase)))
tables.Add(FixTableName(row.ItemArray[2].ToString()));
}
}
}
return tables;
}
/// <summary>
/// Получение информации о таблице по ее имени
/// </summary>
public SqlDbTableInfo GetTableInfo(string table)
{
if (String.IsNullOrEmpty(table))
{
throw new ArgumentNullException("table");
}
var info = new SqlDbTableInfo(FixTableName(table));
info.FillTableInfo(_provider);
return info;
}
#endregion
#endregion
}
}

@ -0,0 +1,28 @@
using System;
using System.Data;
namespace ZeroLevel.SqlServer
{
public class SqlDbMapper : BaseSqlDbMapper
{
protected readonly IDbMapper _mapper;
protected override IDbMapper Mapper
{
get
{
return _mapper;
}
}
public SqlDbMapper(Type entityType, bool as_poco = false) : base(entityType.Name)
{
_mapper = DbMapperFactory.Create(entityType, as_poco);
}
public object Deserialize(DataRow row)
{
return _mapper.Deserialize(row);
}
}
}

@ -0,0 +1,370 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
namespace ZeroLevel.SqlServer
{
public class SqlDbProvider :
IDbProvider
{
#region Fields
private readonly SqlDbConnectionFactory _factory;
private const int Timeout = 60000;
public string ConnectionString
{
get { return _factory.ConnectionString; }
}
public string Server
{
get { return _factory.Server; }
}
public string Base
{
get { return _factory.Base; }
}
#endregion
#region .Ctor
/// <summary>
/// Конструктор.
/// </summary>
public SqlDbProvider(SqlDbConnectionFactory factory)
{
_factory = factory;
}
#endregion
#region ExecuteNonResult
public void ExecuteNonResult(IEnumerable<ZSqlCommand> commands)
{
using (DbConnection connection = _factory.CreateConnection())
{
foreach (var zcmd in commands)
{
using (var cmd = CreateCommand(connection, zcmd.Query, zcmd.Parameters, Timeout))
{
cmd.ExecuteNonQuery();
}
}
}
}
public int ExecuteNonResult(string query)
{
return ExecuteNonResult(query, null);
}
public int ExecuteNonResult(string query, DbParameter[] par)
{
using (DbConnection connection = _factory.CreateConnection())
{
using (var cmd = CreateCommand(connection, query, par, Timeout))
{
return cmd.ExecuteNonQuery();
}
}
}
public T Insert<T>(string insert_query, SqlParameter[] par)
{
DbConnection connection = _factory.CreateConnection();
try
{
using (var cmd = CreateCommand(connection, insert_query, par, Timeout))
{
var result = cmd.ExecuteScalar();
return (T)result;
}
}
finally
{
connection.Dispose();
}
}
#endregion
#region ExecuteQueryDataTable
public DataTable ExecuteQueryDataTable(string query)
{
var ds = ExecuteQuerySqlDataSet(query);
if (ds != null && ds.Tables.Count > 0)
{
return ds.Tables[0];
}
return null;
}
public DataTable ExecuteQueryDataTable(string query, DbParameter[] par)
{
var ds = ExecuteQuerySqlDataSet(query, par);
if (ds != null && ds.Tables.Count > 0)
{
return ds.Tables[0];
}
return null;
}
#endregion
#region ExecuteQuerySqlDataSet
public DataSet ExecuteQuerySqlDataSet(string query)
{
var ds = new DataSet("DataSet");
using (var connection = _factory.CreateConnection())
{
using (var cmd = CreateCommand(connection, query, null, Timeout))
{
using (var da = new SqlDataAdapter(cmd))
{
da.Fill(ds);
}
}
}
return ds;
}
public DataSet ExecuteQuerySqlDataSet(string query, DbParameter[] par)
{
var ds = new DataSet("DataSet");
using (var connection = _factory.CreateConnection())
{
using (var cmd = CreateCommand(connection, query, par, Timeout))
{
using (var da = new SqlDataAdapter(cmd))
{
da.Fill(ds);
}
}
}
return ds;
}
#endregion
#region ExecuteScalar
public object ExecuteScalar(string query)
{
using (var connection = _factory.CreateConnection())
{
using (var cmd = CreateCommand(connection, query, null, Timeout))
{
return cmd.ExecuteScalar();
}
}
}
public object ExecuteScalar(string query, DbParameter[] par)
{
using (var connection = _factory.CreateConnection())
{
using (var cmd = CreateCommand(connection, query, par, Timeout))
{
return cmd.ExecuteScalar();
}
}
}
#endregion
#region ExecuteStoredProcedure
public int ExecProcedure(string name)
{
using (var connection = _factory.CreateConnection())
{
using (var command = new SqlCommand(name, connection)
{
CommandType = CommandType.StoredProcedure
})
{
command.CommandTimeout = 300000;
return command.ExecuteNonQuery();
}
}
}
#endregion
#region LazySelect
public void LazySelect(string query, DbParameter[] par, Func<DbDataReader, bool> readHandler)
{
using (var connection = _factory.CreateConnection())
{
using (var cmd = CreateCommand(connection, query, par, Timeout))
{
using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
try
{
while (reader.Read())
{
if (false == readHandler(reader))
break;
}
}
catch (Exception ex)
{
Log.Error(ex, "Error executing query {0}.", cmd.CommandText);
}
finally
{
// Always call Close when done reading.
reader.Close();
}
}
}
}
}
#endregion
#region ExistsTable
private const string QueryExistsTable = @"IF OBJECT_ID (N'[{0}]', N'U') IS NOT NULL SELECT 1 AS res ELSE SELECT 0 AS res";
public bool ExistsTable(string tableName)
{
return Convert.ToInt32(ExecuteScalar(String.Format(QueryExistsTable, tableName))) == 1;
}
#endregion
#region Commands
private static SqlParameter[] ProcessParameters(DbParameter[] par)
{
if (par != null)
{
var result = new SqlParameter[par.Length];
for (int i = 0; i < par.Length; i++)
{
if (par[i] is SqlParameter)
{
result[i] = (SqlParameter)par[i];
}
else
{
result[i] = new SqlParameter(par[i].ParameterName,
par[i].Value ?? DBNull.Value);
result[i].Size = par[i].Size;
}
}
return result;
}
return new SqlParameter[0];
}
private static SqlCommand CreateCommand(DbConnection connection, string query, DbParameter[] parameters, int timeout)
{
var command = connection.CreateCommand();
command.CommandText = query;
command.CommandType = CommandType.Text;
if (timeout > 0)
command.CommandTimeout = timeout;
if (parameters != null && parameters.Length > 0)
command.Parameters.AddRange(ProcessParameters(parameters));
return (SqlCommand)command;
}
#endregion
#region SQL Server execute plan reset
private const string CLEAN_PLAN_CACHEE_QUERY = "DBCC FREEPROCCACHE WITH NO_INFOMSGS;";
/// <summary>
/// Выполняет удаление всех элементов из кэша планов.
/// Применимо для ускорения работы SQL Server, при очистке кэша создаются новые планы
/// исполнения для новых значений запросов.
/// </summary>
public void CleanPlanCachee()
{
using (var connection = _factory.CreateConnection())
{
using (var cmd = CreateCommand(connection, CLEAN_PLAN_CACHEE_QUERY,
null, Timeout))
{
cmd.ExecuteNonQuery();
}
}
}
#endregion
#region Static methods
/// <summary>
/// Создает базу данных
/// </summary>
/// <param name="server">Сервер</param>
/// <param name="database">Название базы данных</param>
public static void CreateDatabase(string server, string database, string login, string password)
{
if (string.IsNullOrEmpty(server))
{
throw new ArgumentException("Не указано имя сервера");
}
if (string.IsNullOrEmpty(database))
{
throw new ArgumentException("Не указано имя базы данных");
}
using (var connection = new SqlConnection(SqlDbConnectionFactory.BuildConnectionString(server, "master", login, password)))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = String.Format("CREATE DATABASE {0}", database);
command.ExecuteNonQuery();
}
}
}
/// <summary>
/// Выполняет проверку существования базы данных с указанным именем
/// </summary>
public static bool CheckDatabaseExists(string serverName, string databaseName)
{
string sqlExistsDBQuery;
bool result = false;
try
{
using (var tmpConn = new SqlConnection(String.Format("server={0};Trusted_Connection=yes", serverName)))
{
tmpConn.Open();
sqlExistsDBQuery = string.Format("SELECT database_id FROM sys.databases WHERE Name = '{0}'", databaseName);
using (SqlCommand sqlCmd = new SqlCommand(sqlExistsDBQuery, tmpConn))
{
object resultObj = sqlCmd.ExecuteScalar();
int databaseID = 0;
if (resultObj != null)
{
int.TryParse(resultObj.ToString(), out databaseID);
}
result = (databaseID > 0);
}
}
}
catch (Exception ex)
{
Log.Error(ex, "Сбой при попытке подключения к серверу {0} и проверке наличия базы данных {1}",
serverName, databaseName);
result = false;
}
return result;
}
/// <summary>
/// Удаляет базу данных
/// </summary>
public static void DropDatabase(string server, string database, string login, string password)
{
if (string.IsNullOrEmpty(server))
{
throw new ArgumentException("Не указано имя сервера");
}
if (string.IsNullOrEmpty(database))
{
throw new ArgumentException("Не указано имя базы данных");
}
using (var connection = new SqlConnection(SqlDbConnectionFactory.BuildConnectionString(server, "master", login, password)))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = String.Format("ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE;\r\nDROP DATABASE [{1}]", database, database);
command.ExecuteNonQuery();
}
}
}
#endregion
}
}

@ -0,0 +1,510 @@
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.SqlServer
{
public class SqlDbRepository<T>
{
#region Fields
private readonly SqlDbMapper<T> _mapper;
private readonly SqlDbProvider _dbProvider;
#endregion
#region Ctors
public SqlDbRepository(SqlDbConnectionFactory connectionFactory, bool entity_is_poco = false)
{
_mapper = new SqlDbMapper<T>(entity_is_poco);
_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);
}
}
}

@ -0,0 +1,62 @@
using System;
namespace ZeroLevel.SqlServer
{
public class ColumnInfo: IEquatable<ColumnInfo>
{
/// <summary>
/// Наименование поля
/// </summary>
public string Name { get; set; }
/// <summary>
/// Тип поля в рамках базы данных
/// </summary>
public string DbType;
/// <summary>
/// Тип поля в рамках .NET
/// </summary>
public Type DotNetType;
/// <summary>
/// Указывает что поле является ключом таблицы
/// </summary>
public bool IsPrimaryKey;
/// <summary>
/// Указывает, разрешены ли значения NULL в поле
/// </summary>
public bool AllowNull;
/// <summary>
/// Размер в байтах (если применимо)
/// </summary>
public long Size;
/// <summary>
/// Указывает что поле является автоинкрементируемым
/// </summary>
public bool AutoInc;
public ColumnInfo() { }
public ColumnInfo(ColumnInfo other)
{
Name = other.Name;
DbType = other.DbType;
DotNetType = other.DotNetType;
IsPrimaryKey = other.IsPrimaryKey;
AllowNull = other.AllowNull;
Size = other.Size;
AutoInc = other.AutoInc;
}
public bool Equals(ColumnInfo other)
{
bool eq = true;
eq &= AutoInc == other.AutoInc;
eq &= Size == other.Size;
eq &= AllowNull == other.AllowNull;
eq &= IsPrimaryKey == other.IsPrimaryKey;
eq &= String.Compare(DbType, other.DbType, StringComparison.OrdinalIgnoreCase) == 0;
eq &= String.Compare(Name, other.Name, StringComparison.OrdinalIgnoreCase) == 0;
eq &= DotNetType.Equals(other.DotNetType);
return eq;
}
}
}

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using ZeroLevel.Services.Collections;
namespace ZeroLevel.SqlServer
{
public class IndexInfo : IEquatable<IndexInfo>
{
public string Name;
public List<string> Columns = new List<string>();
public bool IsUnique;
public bool IsPrimaryKey;
public bool Equals(IndexInfo other)
{
bool eq = true;
eq &= String.Compare(Name, other.Name, StringComparison.Ordinal) == 0;
eq &= Columns.NoOrderingEquals(other.Columns);
eq &= IsUnique == other.IsUnique;
eq &= IsPrimaryKey == other.IsPrimaryKey;
return eq;
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
}

@ -0,0 +1,33 @@
using System;
namespace ZeroLevel.SqlServer
{
public sealed class SqlDbForeignKeyInfo : IEquatable<SqlDbForeignKeyInfo>
{
public const string ForeignKeySelectQuery = "SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME";
public string ForeignKeyName;
public string ForeignKeyTable;
public string PrimaryKeyTable;
public string ForeignKeyColumn;
public string PrimaryKeyColumn;
public bool Equals(SqlDbForeignKeyInfo other)
{
return String.Compare(ForeignKeyName, other.ForeignKeyName, StringComparison.OrdinalIgnoreCase) == 0 &&
String.Compare(ForeignKeyTable, other.ForeignKeyTable, StringComparison.OrdinalIgnoreCase) == 0 &&
String.Compare(PrimaryKeyTable, other.PrimaryKeyTable, StringComparison.OrdinalIgnoreCase) == 0 &&
String.Compare(ForeignKeyColumn, other.ForeignKeyColumn, StringComparison.OrdinalIgnoreCase) == 0 &&
String.Compare(PrimaryKeyColumn, other.PrimaryKeyColumn, StringComparison.OrdinalIgnoreCase) == 0;
}
public override int GetHashCode()
{
return ForeignKeyName.GetHashCode() ^
ForeignKeyTable.GetHashCode() ^
PrimaryKeyTable.GetHashCode() ^
ForeignKeyColumn.GetHashCode() ^
PrimaryKeyColumn.GetHashCode();
}
}
}

@ -0,0 +1,38 @@
namespace ZeroLevel.SqlServer
{
public struct SqlDbObjectInfo
{
public string Name;
public string Header;
public string Text;
public static bool operator ==(SqlDbObjectInfo first, SqlDbObjectInfo second)
{
return first.Equals(second);
}
public static bool operator !=(SqlDbObjectInfo first, SqlDbObjectInfo second)
{
return !first.Equals(second);
}
public bool Equals(SqlDbObjectInfo other)
{
bool eq = true;
eq &= string.Compare(Name, other.Name, System.StringComparison.Ordinal) == 0;
eq &= string.Compare(Header, other.Header, System.StringComparison.Ordinal) == 0;
eq &= string.Compare(Text, other.Text, System.StringComparison.Ordinal) == 0;
return eq;
}
public override bool Equals(object obj)
{
return Equals((SqlDbObjectInfo)obj);
}
public override int GetHashCode()
{
return Name.GetHashCode() ^ Header.GetHashCode() ^ Text.GetHashCode();
}
}
}

@ -0,0 +1,21 @@
using System;
namespace ZeroLevel.SqlServer
{
public sealed class SqlDbPrimaryKeyInfo : IEquatable<SqlDbPrimaryKeyInfo>
{
public string PrimaryKeyTable;
public string PrimaryKeyColumn;
public bool Equals(SqlDbPrimaryKeyInfo other)
{
return String.Compare(PrimaryKeyTable, other.PrimaryKeyTable, StringComparison.OrdinalIgnoreCase) == 0 &&
String.Compare(PrimaryKeyColumn, other.PrimaryKeyColumn, StringComparison.OrdinalIgnoreCase) == 0;
}
public override int GetHashCode()
{
return PrimaryKeyTable.GetHashCode() ^ PrimaryKeyColumn.GetHashCode();
}
}
}

@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
namespace ZeroLevel.SqlServer
{
/// <summary>
/// Описание таблицы в БД
/// </summary>
public sealed class SqlDbTableInfo : TableInfo, IEquatable<SqlDbTableInfo>
{
#region Ctor
/// <summary>
/// Конструктор по-умолчанию
/// </summary>
/// <param name="name"></param>
public SqlDbTableInfo(string name) : base(name)
{
}
/// <summary>
/// Конструктор по-умолчанию
/// </summary>
/// <param name="name"></param>
public SqlDbTableInfo(SqlDbTableInfo other) : base(other)
{
}
#endregion
#region IEquatable
/// <summary>
/// Сравнение с другой таблицей
/// </summary>
public bool Equals(SqlDbTableInfo other)
{
return base.Equals(other);
}
#endregion
#region Fill table info
protected override IEnumerable<IndexInfo> GetIndexes(IDbProvider db)
{
var indexes = new List<IndexInfo>();
string select = "exec sp_indexes_rowset [{0}]";
using (var ds = db.ExecuteQuerySqlDataSet(string.Format(select, _name)))
{
using (var indexInfo = ds.Tables[0])
{
foreach (DataRow row in indexInfo.Rows)
{
var i = new IndexInfo
{
Name = (string)row["INDEX_NAME"],
IsPrimaryKey = (bool)row["PRIMARY_KEY"],
IsUnique = (bool)row["UNIQUE"]
};
i.Columns.Add((string)row["COLUMN_NAME"]);
indexes.Add(i);
}
}
}
return indexes;
}
protected override IEnumerable<ColumnInfo> GetColumns(IDbProvider db)
{
// Для уменьшения количества обращения к базе все данные по таблице в одном запросе
var columns = new List<ColumnInfo>();
string select = @"exec sp_columns [{0}]
SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='{0}'
exec sp_pkeys @table_name = [{0}]";
using (var ds = db.ExecuteQuerySqlDataSet(string.Format(select, _name)))
{
if (ds.Tables.Count != 3)
{
throw new InvalidOperationException("Не удалось получить данные по таблице " + _name);
}
var columnTypes = new Dictionary<string, string>();
var columnSize = new Dictionary<string, long>();
using (var dataTypeInfo = ds.Tables[1])
{
foreach (DataRow row in dataTypeInfo.Rows)
{
columnTypes.Add((string)row["COLUMN_NAME"], (string)row["DATA_TYPE"]);
var maximum = row["CHARACTER_MAXIMUM_LENGTH"];
columnSize.Add((string)row["COLUMN_NAME"], (maximum != DBNull.Value) ? Convert.ToInt64(row["CHARACTER_MAXIMUM_LENGTH"]) : 0);
}
}
using (var tableInfo = ds.Tables[0])
{
foreach (DataRow row in tableInfo.Rows)
{
var column = new ColumnInfo();
column.Name = (string)row["COLUMN_NAME"];
column.Size = columnSize[column.Name];
column.DbType = columnTypes[column.Name];
column.AllowNull = (short)row["NULLABLE"] == 1;
column.DotNetType = DbTypeMapper.ToClrType(columnTypes[column.Name]);
column.AutoInc = ((string)row["TYPE_NAME"]).Contains("identity");
columns.Add(column);
}
}
using (var pkInfo = ds.Tables[2])
{
if (pkInfo.Rows.Count > 0 && pkInfo.Rows[0].ItemArray.Length > 3)
{
var primaryKeyName = pkInfo.Rows[0][3].ToString();
var pc = columns.First(c => c.Name.Equals(primaryKeyName, StringComparison.OrdinalIgnoreCase));
pc.IsPrimaryKey = true;
}
}
}
return columns;
}
#endregion
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}

@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace ZeroLevel.SqlServer
{
public abstract class TableInfo : IEquatable<TableInfo>
{
#region Private fields
/// <summary>
/// Имя таблицы
/// </summary>
protected readonly string _name;
/// <summary>
/// Поле-идентификатор
/// </summary>
private ColumnInfo _primaryKey;
/// <summary>
/// Все поля таблицы
/// </summary>
private readonly Dictionary<string, ColumnInfo> _columns = new Dictionary<string, ColumnInfo>();
/// <summary>
/// Индексы
/// </summary>
private readonly List<IndexInfo> _indexes = new List<IndexInfo>();
#endregion
#region Properties
public ColumnInfo this[string columnName]
{
get
{
if (_columns.ContainsKey(columnName))
{
return _columns[columnName];
}
return null;
}
}
/// <summary>
/// Первичный ключ
/// </summary>
public ColumnInfo PrimaryKey
{
get { return _primaryKey; }
}
/// <summary>
/// Имя таблицы
/// </summary>
public string Name
{
get
{
return _name;
}
}
/// <summary>
/// Индексы
/// </summary>
public List<IndexInfo> Indexes
{
get
{
return _indexes;
}
}
/// <summary>
/// Поля таблицы
/// </summary>
public IEnumerable<ColumnInfo> Columns
{
get
{
return _columns.Values;
}
}
#endregion
#region Ctor
/// <summary>
/// Конструктор по-умолчанию
/// </summary>
/// <param name="name"></param>
public TableInfo(string name)
{
_name = name;
}
/// <summary>
/// Конструктор по-умолчанию
/// </summary>
/// <param name="name"></param>
public TableInfo(TableInfo other)
{
_name = other._name;
_columns = new Dictionary<string, ColumnInfo>(other._columns);
_indexes = new List<IndexInfo>(other._indexes);
_primaryKey = other._primaryKey;
}
#endregion
#region IEquatable
public override bool Equals(object obj)
{
return this.Equals(obj as TableInfo);
}
/// <summary>
/// Сравнение с другой таблицей
/// </summary>
public bool Equals(TableInfo other)
{
if (other == null || _name.Equals(other._name, StringComparison.OrdinalIgnoreCase) == false)
return false;
if (false == Columns.NoOrderingEquals(other.Columns))
{
return false;
}
return true;
}
#endregion
#region Abstract
protected abstract IEnumerable<IndexInfo> GetIndexes(IDbProvider db);
protected abstract IEnumerable<ColumnInfo> GetColumns(IDbProvider db);
#endregion
#region Fill table info
public void AppendNewColumn(ColumnInfo column)
{
_columns.Add(column.Name, column);
if (column.IsPrimaryKey)
_primaryKey = column;
}
/// <summary>
/// Заполнение данных о таблице
/// </summary>
/// <param name="db">Подключение к базе данных</param>
public void FillTableInfo(IDbProvider db)
{
foreach (var column in GetColumns(db))
{
_columns.Add(column.Name, column);
if (column.IsPrimaryKey)
{
_primaryKey = column;
}
}
foreach (var index in GetIndexes(db))
{
_indexes.Add(index);
}
}
#endregion
/// <summary>
/// Проверка наличия поля
/// </summary>
public bool ContainsColumns(ColumnInfo column)
{
return Columns.Any(r => r.Equals(column));
}
/// <summary>
/// Проверка наличия поля
/// </summary>
public bool ContainsColumns(string columnName)
{
return Columns.Any(r => r.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase));
}
public override int GetHashCode()
{
return _name.GetHashCode();
}
}
}

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A8AD956F-1559-45EC-A7DB-42290494E2C5}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ZeroLevel.SqlServer</RootNamespace>
<AssemblyName>ZeroLevel.SqlServer</AssemblyName>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="ZeroLevel, Version=2.0.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ZeroLevel.2.0.8\lib\netstandard2.0\ZeroLevel.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Contracts\BaseEntity.cs" />
<Compile Include="Contracts\BaseVersionedEntity.cs" />
<Compile Include="Contracts\DbIndexAttribute.cs" />
<Compile Include="Contracts\DbMemberAttribute.cs" />
<Compile Include="Contracts\IDbField.cs" />
<Compile Include="Contracts\IDbMapper.cs" />
<Compile Include="Contracts\IDbProvider.cs" />
<Compile Include="Contracts\IEntity.cs" />
<Compile Include="Contracts\IVersionedEntity.cs" />
<Compile Include="Contracts\ZSqlCommand.cs" />
<Compile Include="DbField.cs" />
<Compile Include="DbMapper.cs" />
<Compile Include="DbMapperFactory.cs" />
<Compile Include="DbTypeMapper.cs" />
<Compile Include="DDD\IdentitySpecification.cs" />
<Compile Include="GenericDbMapper.cs" />
<Compile Include="ISqlServerSpecification.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="BaseSqlDbMapper.cs" />
<Compile Include="GenericSqlDbMapper.cs" />
<Compile Include="SqlDbConnectionFactory.cs" />
<Compile Include="SqlDbInfo.cs" />
<Compile Include="SqlDbMapper.cs" />
<Compile Include="SqlDbProvider.cs" />
<Compile Include="SqlDbRepository.cs" />
<Compile Include="DDD\SqlIdentitySpecification.cs" />
<Compile Include="SqlServerEntities\ColumnInfo.cs" />
<Compile Include="SqlServerEntities\IndexInfo.cs" />
<Compile Include="SqlServerEntities\SqlDbForeignKeyInfo.cs" />
<Compile Include="SqlServerEntities\SqlDbObjectInfo.cs" />
<Compile Include="SqlServerEntities\SqlDbPrimaryKeyInfo.cs" />
<Compile Include="SqlServerEntities\SqlDbTableInfo.cs" />
<Compile Include="SqlServerEntities\TableInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ZeroLevel" version="2.0.8" targetFramework="net47" />
</packages>

@ -17,36 +17,102 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTransferClient", "FileT
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTransferServer", "FileTransferServer\FileTransferServer.csproj", "{9BF859EE-EF90-4B5B-8576-E26770F2F792}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTransferServer", "FileTransferServer\FileTransferServer.csproj", "{9BF859EE-EF90-4B5B-8576-E26770F2F792}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroLevel.SqlServer", "ZeroLevel.SqlServer\ZeroLevel.SqlServer.csproj", "{A8AD956F-1559-45EC-A7DB-42290494E2C5}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Debug|Any CPU.Build.0 = Debug|Any CPU {06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Debug|x64.ActiveCfg = Debug|Any CPU
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Debug|x64.Build.0 = Debug|Any CPU
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Debug|x86.ActiveCfg = Debug|Any CPU
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Debug|x86.Build.0 = Debug|Any CPU
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Release|Any CPU.ActiveCfg = Release|Any CPU {06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Release|Any CPU.Build.0 = Release|Any CPU {06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Release|Any CPU.Build.0 = Release|Any CPU
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Release|x64.ActiveCfg = Release|Any CPU
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Release|x64.Build.0 = Release|Any CPU
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Release|x86.ActiveCfg = Release|Any CPU
{06C9E60E-D449-41A7-9BF0-A829AAF5D214}.Release|x86.Build.0 = Release|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E5595DE0-B177-4078-AD10-8D3135014838}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Debug|Any CPU.Build.0 = Debug|Any CPU {E5595DE0-B177-4078-AD10-8D3135014838}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Debug|x64.ActiveCfg = Debug|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Debug|x64.Build.0 = Debug|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Debug|x86.ActiveCfg = Debug|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Debug|x86.Build.0 = Debug|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Release|Any CPU.ActiveCfg = Release|Any CPU {E5595DE0-B177-4078-AD10-8D3135014838}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Release|Any CPU.Build.0 = Release|Any CPU {E5595DE0-B177-4078-AD10-8D3135014838}.Release|Any CPU.Build.0 = Release|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Release|x64.ActiveCfg = Release|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Release|x64.Build.0 = Release|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Release|x86.ActiveCfg = Release|Any CPU
{E5595DE0-B177-4078-AD10-8D3135014838}.Release|x86.Build.0 = Release|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {674561F2-A3E2-40E6-8E5B-AD94276AD856}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Debug|Any CPU.Build.0 = Debug|Any CPU {674561F2-A3E2-40E6-8E5B-AD94276AD856}.Debug|Any CPU.Build.0 = Debug|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Debug|x64.ActiveCfg = Debug|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Debug|x64.Build.0 = Debug|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Debug|x86.ActiveCfg = Debug|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Debug|x86.Build.0 = Debug|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Release|Any CPU.ActiveCfg = Release|Any CPU {674561F2-A3E2-40E6-8E5B-AD94276AD856}.Release|Any CPU.ActiveCfg = Release|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Release|Any CPU.Build.0 = Release|Any CPU {674561F2-A3E2-40E6-8E5B-AD94276AD856}.Release|Any CPU.Build.0 = Release|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Release|x64.ActiveCfg = Release|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Release|x64.Build.0 = Release|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Release|x86.ActiveCfg = Release|Any CPU
{674561F2-A3E2-40E6-8E5B-AD94276AD856}.Release|x86.Build.0 = Release|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5CE51CC9-7884-4E21-9D68-2321CA14312E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Debug|Any CPU.Build.0 = Debug|Any CPU {5CE51CC9-7884-4E21-9D68-2321CA14312E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Debug|x64.ActiveCfg = Debug|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Debug|x64.Build.0 = Debug|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Debug|x86.ActiveCfg = Debug|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Debug|x86.Build.0 = Debug|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Release|Any CPU.ActiveCfg = Release|Any CPU {5CE51CC9-7884-4E21-9D68-2321CA14312E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Release|Any CPU.Build.0 = Release|Any CPU {5CE51CC9-7884-4E21-9D68-2321CA14312E}.Release|Any CPU.Build.0 = Release|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Release|x64.ActiveCfg = Release|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Release|x64.Build.0 = Release|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Release|x86.ActiveCfg = Release|Any CPU
{5CE51CC9-7884-4E21-9D68-2321CA14312E}.Release|x86.Build.0 = Release|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F8B727E1-340D-4096-A784-E570AE13FABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Debug|Any CPU.Build.0 = Debug|Any CPU {F8B727E1-340D-4096-A784-E570AE13FABC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Debug|x64.ActiveCfg = Debug|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Debug|x64.Build.0 = Debug|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Debug|x86.ActiveCfg = Debug|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Debug|x86.Build.0 = Debug|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Release|Any CPU.ActiveCfg = Release|Any CPU {F8B727E1-340D-4096-A784-E570AE13FABC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Release|Any CPU.Build.0 = Release|Any CPU {F8B727E1-340D-4096-A784-E570AE13FABC}.Release|Any CPU.Build.0 = Release|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Release|x64.ActiveCfg = Release|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Release|x64.Build.0 = Release|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Release|x86.ActiveCfg = Release|Any CPU
{F8B727E1-340D-4096-A784-E570AE13FABC}.Release|x86.Build.0 = Release|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9BF859EE-EF90-4B5B-8576-E26770F2F792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Debug|Any CPU.Build.0 = Debug|Any CPU {9BF859EE-EF90-4B5B-8576-E26770F2F792}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Debug|x64.ActiveCfg = Debug|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Debug|x64.Build.0 = Debug|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Debug|x86.ActiveCfg = Debug|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Debug|x86.Build.0 = Debug|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Release|Any CPU.ActiveCfg = Release|Any CPU {9BF859EE-EF90-4B5B-8576-E26770F2F792}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Release|Any CPU.Build.0 = Release|Any CPU {9BF859EE-EF90-4B5B-8576-E26770F2F792}.Release|Any CPU.Build.0 = Release|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Release|x64.ActiveCfg = Release|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Release|x64.Build.0 = Release|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Release|x86.ActiveCfg = Release|Any CPU
{9BF859EE-EF90-4B5B-8576-E26770F2F792}.Release|x86.Build.0 = Release|Any CPU
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Debug|x64.ActiveCfg = Debug|x64
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Debug|x64.Build.0 = Debug|x64
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Debug|x86.ActiveCfg = Debug|x86
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Debug|x86.Build.0 = Debug|x86
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Release|Any CPU.Build.0 = Release|Any CPU
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Release|x64.ActiveCfg = Release|x64
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Release|x64.Build.0 = Release|x64
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Release|x86.ActiveCfg = Release|x86
{A8AD956F-1559-45EC-A7DB-42290494E2C5}.Release|x86.Build.0 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

Loading…
Cancel
Save

Powered by TurnKey Linux.