/// <summary>
        /// Initializes a new instance of the <see cref="TableEqualityComparer{T}"/> class.
        /// </summary>
        /// <param name="typeInfo">The information about the table.</param>
        public TableEqualityComparer(SqlTypeInfo typeInfo)
        {
            InitialHash    = typeInfo.FullyQualifiedTableName.GetHashCode() * -1977;
            StringComparer = typeInfo.Adapter.StringComparer;
            List <MemberGetter> stringGetters = new List <MemberGetter>();
            List <MemberGetter> otherGetters  = new List <MemberGetter>();
            List <MemberGetter> byteGetters   = new List <MemberGetter>();

            foreach (SqlColumn column in typeInfo.EqualityColumns)
            {
                MemberGetter getter = column.Getter;
                if (column.Type == typeof(byte[]))
                {
                    byteGetters.Add(getter);
                }
                else if (column.Type == typeof(string) && StringComparer != System.StringComparer.Ordinal)
                {
                    stringGetters.Add(getter);
                }
                else
                {
                    otherGetters.Add(getter);
                }
            }
            StringGetters    = stringGetters.Count == 0 ? Array.Empty <MemberGetter>() : stringGetters.ToArray();
            Getters          = otherGetters.Count == 0 ? Array.Empty <MemberGetter>() : otherGetters.ToArray();
            ByteArrayGetters = byteGetters.Count == 0 ? Array.Empty <MemberGetter>() : byteGetters.ToArray();
        }
Example #2
0
        /// <summary>
        /// Creates or gets a cached <see cref="SqlBuilder{T}"/>.
        /// </summary>
        /// <typeparam name="T">The table type.</typeparam>
        /// <returns>The <see cref="SqlBuilder{T}"/>.</returns>
        public static SqlBuilder <T> Builder <T>() where T : class
        {
            Type type = typeof(T);

            if (BuilderCache.TryGetValue(type, out object obj))
            {
                return((SqlBuilder <T>)obj);
            }
            SqlTypeInfo    typeInfo = new SqlTypeInfo(type, Dialect);
            SqlBuilder <T> builder  = new SqlBuilder <T>(typeInfo);

            return((SqlBuilder <T>)BuilderCache.GetOrAdd(type, builder));
        }
        /// <summary>
        /// Converts a list of objects to a list of CSV rows.
        /// </summary>
        /// <typeparam name="T">The type of object.</typeparam>
        /// <param name="list">A list of objects to convert to a csv.</param>
        /// <param name="separater">The separater between each value.</param>
        /// <param name="printColumnNames">Determines if the column names should be printed.</param>
        /// <returns>A list of CSV rows.</returns>
        public static IEnumerable <string> ToCsv <T>(IEnumerable <T> list, string separater = ",", bool printColumnNames = true) where T : class
        {
            SqlTypeInfo typeInfo = ExtraCrud.TypeInfo <T>();
            IReadOnlyList <SqlColumn> columns = typeInfo.AutoKeyColumn == null ? typeInfo.Columns : typeInfo.Columns.Where(c => !c.IsAutoKey).ToArray();

            if (columns.Count != 0)
            {
                MemberGetter[] getters = new MemberGetter[columns.Count];
                StringBuilder  sb      = new StringBuilder();
                for (int i = 0; i < columns.Count; i++)
                {
                    SqlColumn column = columns[i];
                    getters[i] = columns[i].Getter;
                    sb.Append('\"').Append(column.ColumnName.Replace("\"", "\"\"")).Append('\"').Append(separater);
                }
                sb.Remove(sb.Length - separater.Length, separater.Length);
                if (printColumnNames)
                {
                    yield return(sb.ToString());
                }
                foreach (T obj in list)
                {
                    sb.Clear();
                    foreach (MemberGetter getter in getters)
                    {
                        object value = getter(obj);
                        if (value == null)
                        {
                            sb.Append("NULL");
                        }
                        else
                        {
                            sb.Append('\"').Append(value.ToString().Replace("\"", "\"\"")).Append('\"');
                        }
                        sb.Append(separater);
                    }
                    sb.Remove(sb.Length - separater.Length, separater.Length);
                    yield return(sb.ToString());
                }
            }
        }
Example #4
0
        /// <summary>
        /// Sets the adapter for the queries/builder. This can be a custom adapter. The builder
        /// for the given type will be purged from the cache if it is not using the given adapter.
        /// </summary>
        /// <typeparam name="T">The table type.</typeparam>
        /// <param name="adapter">The adapter used to generate SQL commands.</param>
        public static void SetAdapter <T>(ISqlAdapter adapter) where T : class
        {
            if (adapter == null)
            {
                throw new ArgumentNullException(nameof(adapter));
            }
            Type           type = typeof(T);
            SqlBuilder <T> builder;

            if (BuilderCache.TryGetValue(type, out object obj))
            {
                builder = (SqlBuilder <T>)obj;
                if (ReferenceEquals(builder.Info.Adapter, adapter))
                {
                    return;
                }
            }
            SqlTypeInfo typeInfo = new SqlTypeInfo(type, adapter);

            builder = new SqlBuilder <T>(typeInfo);
            BuilderCache.AddOrUpdate(type, builder, (t, old) => builder);
        }
Example #5
0
		/// <summary>
		/// Initializes a new instance of the <see cref="SqlBuilder{T}"/> class.
		/// </summary>
		/// <param name="typeInfo">The information about the table.</param>
		/// <param name="threadSafety">The thread safety level to assign the lazy delegates.</param>
		public SqlBuilder(SqlTypeInfo typeInfo, LazyThreadSafetyMode threadSafety = LazyThreadSafetyMode.ExecutionAndPublication)
		{
			if (typeInfo.Type.IsGenericTypeDefinition && typeInfo.Type.GetGenericTypeDefinition() == typeof(List<>))
				throw new InvalidOperationException("List<> is not a valid table type.");
			if (typeInfo.Type.IsArray)
				throw new InvalidOperationException("Array<> is not a valid table type.");
			if (typeInfo.Type == typeof(string))
				throw new InvalidOperationException("String is not a valid table type.");
			Info = typeInfo;
			BulkStagingTable = Info.Adapter.CreateTempTableName(Info.Type.Name + (Math.Abs(Info.Type.FullName.GetHashCode()) % 99793));
			SqlQueries<T> queries = new SqlQueries<T>() {
				InsertAutoSync = CreateAutoSync(Info.InsertAutoSyncColumns),
				UpdateAutoSync = CreateAutoSync(typeInfo.UpdateAutoSyncColumns),
				LazyUpdateObj = new Lazy<DbObjBool<T>>(() => CreateUpdateObj()),
				LazyBulkDelete = new Lazy<DbListInt<T>>(() => CreateBulkDelete(), threadSafety),
				LazyBulkGet = new Lazy<DbListList<T>>(() => CreateBulkGet(), threadSafety),
				LazyBulkInsert = new Lazy<DbListVoid<T>>(() => CreateBulkInsert(), threadSafety),
				LazyBulkInsertIfNotExists = new Lazy<DbListInt<T>>(() => CreateBulkInsertIfNotExists(), threadSafety),
				LazyBulkUpdate = new Lazy<DbListInt<T>>(() => CreateBulkUpdate(), threadSafety),
				LazyBulkUpsert = new Lazy<DbListInt<T>>(() => CreateBulkUpsert(), threadSafety),
				LazyTruncate = new Lazy<DbVoid>(() => CreateTruncate(), threadSafety),
				LazyDeleteList = new Lazy<DbWhereInt<T>>(() => CreateDeleteList(), threadSafety),
				LazyGetDistinct = new Lazy<DbTypeWhereList<T>>(() => CreateGetDistinct(), threadSafety),
				LazyGetDistinctLimit = new Lazy<DbTypeLimitList<T>>(() => CreateGetDistinctLimit(), threadSafety),
				LazyGetKeys = new Lazy<DbWhereList<T>>(() => CreateGetKeys(), threadSafety),
				LazyGetLimit = new Lazy<DbLimitList<T>>(() => CreateGetLimit(), threadSafety),
				LazyInsertIfNotExists = new Lazy<DbTBool<T>>(() => CreateInsertIfNotExists(), threadSafety),
				LazyRecordCount = new Lazy<DbWhereInt<T>>(() => CreateRecordCount(), threadSafety),
				LazyUpsert = new Lazy<DbTBool<T>>(() => CreateUpsert(), threadSafety),
				LazyGetFilter = new Lazy<DbTypeWhereList<T>>(() => CreateGetFilterList(), threadSafety),
				LazyGetFilterLimit = new Lazy<DbTypeLimitList<T>>(() => CreateGetFilterLimit(), threadSafety),
			};
			Queries = queries;
			queries.Insert = CreateInsert();
			queries.Update = CreateUpdate();
			queries.Delete = CreateDelete();
			queries.Get = CreateGet();
			queries.GetList = CreateGetList();
			DataReaderFactory = new DataReaderFactory(typeof(T), typeInfo.Columns.Where(c => c.Getter != null).Select(c => c.Property));

			if (typeInfo.EqualityColumns.Count == 1) {
				if ((EqualityColumns[0].Type == typeof(string) && Adapter.StringComparer != StringComparer.Ordinal) || EqualityColumns[0].Type == typeof(byte[]))
					EqualityComparer = new TableEqualityComparer<T>(Info);
				else
					EqualityComparer = new TableKeyEqualityComparer<T>(FullyQualifiedTableName, EqualityColumns[0]);
				Type type = typeInfo.EqualityColumns[0].Type;
				TypeCode typeCode = Type.GetTypeCode(type);
				switch (typeCode) {
					case TypeCode.Int16:
						Create<short>(threadSafety);
						break;
					case TypeCode.Int32:
						Create<int>(threadSafety);
						break;
					case TypeCode.Int64:
						Create<long>(threadSafety);
						break;
					case TypeCode.SByte:
						Create<sbyte>(threadSafety);
						break;
					case TypeCode.Single:
						Create<float>(threadSafety);
						break;
					case TypeCode.String:
						Create<string>(threadSafety);
						break;
					case TypeCode.UInt16:
						Create<ushort>(threadSafety);
						break;
					case TypeCode.Double:
						Create<double>(threadSafety);
						break;
					case TypeCode.UInt32:
						Create<uint>(threadSafety);
						break;
					case TypeCode.UInt64:
						Create<ulong>(threadSafety);
						break;
					case TypeCode.Byte:
						Create<byte>(threadSafety);
						break;
					case TypeCode.Char:
						Create<char>(threadSafety);
						break;
					case TypeCode.DateTime:
						Create<DateTime>(threadSafety);
						break;
					case TypeCode.Decimal:
						Create<decimal>(threadSafety);
						break;
					default:
						if (type == typeof(Guid))
							Create<Guid>(threadSafety);
						else if (type == typeof(DateTimeOffset))
							Create<DateTimeOffset>(threadSafety);
						else if (type == typeof(TimeSpan))
							Create<TimeSpan>(threadSafety);
						else if (type == typeof(byte[]))
							Create<byte[]>(threadSafety);
						else
							Create("Unsupported SQL key type: " + type, threadSafety);
						break;
				}
			}
			else {
				EqualityComparer = new TableEqualityComparer<T>(Info);
				Create("Composite key does not support this operation", threadSafety);
			}
			string paramsSelect = ParamsSelect(Info.SelectColumns);
			SelectMap.GetOrAdd(typeof(T), paramsSelect);
		}
Example #6
0
        /// <summary>
        /// Creates or gets a cached <see cref="SqlTypeInfo"/>.
        /// </summary>
        /// <typeparam name="T">The table type.</typeparam>
        /// <returns>The <see cref="SqlTypeInfo"/>.</returns>
        public static SqlTypeInfo TypeInfo <T>() where T : class
        {
            SqlTypeInfo typeInfo = Builder <T>().Info;

            return(typeInfo);
        }