Beispiel #1
0
        private void InitProperties()
        {
            var entityType          = typeof(TEntity);
            var entityTypeInfo      = entityType.GetTypeInfo();
            var tableAliasAttribute = entityTypeInfo.GetCustomAttribute <TableAttribute>();

            TableName = tableAliasAttribute != null ? tableAliasAttribute.Name : entityTypeInfo.Name;

            AllProperties = entityType.GetProperties().Where(q => q.CanWrite).ToArray();
            var props = AllProperties.Where(ExpressionHelper.GetPrimitivePropertiesPredicate()).ToArray();

            // Filter the non stored properties
            SqlProperties = props.Where(p => !p.GetCustomAttributes <NotMappedAttribute>().Any()).Select(p => new SqlPropertyMetadata(p)).ToArray();

            // Filter key properties
            KeySqlProperties = props.Where(p => p.GetCustomAttributes <KeyAttribute>().Any()).Select(p => new SqlPropertyMetadata(p)).ToArray();

            // Use identity as key pattern
            var identityProperty = props.FirstOrDefault(p => p.GetCustomAttributes <IdentityAttribute>().Any());

            IdentitySqlProperty = identityProperty != null ? new SqlPropertyMetadata(identityProperty) : null;

            var dateChangedProperty = props.FirstOrDefault(p => p.GetCustomAttributes <DateChangedAttribute>().Count() == 1);

            if (dateChangedProperty != null && (dateChangedProperty.PropertyType == typeof(DateTime) || dateChangedProperty.PropertyType == typeof(DateTime?)))
            {
                DateChangedProperty = props.FirstOrDefault(p => p.GetCustomAttributes <DateChangedAttribute>().Any());
            }
        }
        /// <summary>
        ///     Get join/nested properties
        /// </summary>
        /// <returns></returns>
        private static SqlJoinPropertyMetadata[] GetJoinPropertyMetadata(PropertyInfo[] joinPropertiesInfo)
        {
            // Filter and get only non collection nested properties
            var singleJoinTypes = joinPropertiesInfo.Where(p => !p.PropertyType.IsConstructedGenericType).ToArray();

            var joinPropertyMetadatas = new List <SqlJoinPropertyMetadata>();

            foreach (var propertyInfo in singleJoinTypes)
            {
                var joinInnerProperties = propertyInfo.PropertyType.GetProperties().Where(q => q.CanWrite)
                                          .Where(ExpressionHelper.GetPrimitivePropertiesPredicate()).ToArray();
                joinPropertyMetadatas.AddRange(joinInnerProperties.Where(p => !p.GetCustomAttributes <NotMappedAttribute>().Any())
                                               .Select(p => new SqlJoinPropertyMetadata(propertyInfo, p)).ToArray());
            }

            return(joinPropertyMetadatas.ToArray());
        }
Beispiel #3
0
        private StringBuilder AppendJoinToSelect(StringBuilder originalBuilder, params Expression <Func <TEntity, object> >[] includes)
        {
            var joinsBuilder = new StringBuilder();

            foreach (var include in includes)
            {
                var propertyName = ExpressionHelper.GetPropertyName(include);
                var joinProperty = AllProperties.First(x => x.Name == propertyName);
                var attrJoin     = joinProperty.GetCustomAttribute <JoinAttributeBase>();
                if (attrJoin != null)
                {
                    var joinString = "";
                    if (attrJoin is LeftJoinAttribute)
                    {
                        joinString = "LEFT JOIN ";
                    }
                    else if (attrJoin is InnerJoinAttribute)
                    {
                        joinString = "INNER JOIN ";
                    }
                    else if (attrJoin is RightJoinAttribute)
                    {
                        joinString = "RIGHT JOIN ";
                    }

                    var joinType = joinProperty.PropertyType.IsGenericType() ? joinProperty.PropertyType.GenericTypeArguments[0] : joinProperty.PropertyType;

                    var properties = joinType.GetProperties().Where(ExpressionHelper.GetPrimitivePropertiesPredicate());
                    var props      = properties.Where(p => !p.GetCustomAttributes <NotMappedAttribute>().Any()).Select(p => new PropertyMetadata(p));
                    originalBuilder.Append(", " + GetFieldsSelect(attrJoin.TableName, props));


                    joinsBuilder.Append($"{joinString} {attrJoin.TableName} ON {TableName}.{attrJoin.Key} = {attrJoin.TableName}.{attrJoin.ExternalKey} ");
                }
            }
            return(joinsBuilder);
        }
        private void InitProperties()
        {
            var entityType     = typeof(TEntity);
            var entityTypeInfo = entityType.GetTypeInfo();
            var tableAttribute = entityTypeInfo.GetCustomAttribute <TableAttribute>();

            TableName   = tableAttribute != null ? tableAttribute.Name : entityTypeInfo.Name;
            TableSchema = tableAttribute != null ? tableAttribute.Schema : string.Empty;

            AllProperties = entityType.FindClassProperties().Where(q => q.CanWrite).ToArray();

            var props = AllProperties.Where(ExpressionHelper.GetPrimitivePropertiesPredicate()).ToArray();

            var joinProperties = AllProperties.Where(p => p.GetCustomAttributes <JoinAttributeBase>().Any()).ToArray();

            SqlJoinProperties = GetJoinPropertyMetadata(joinProperties);

            // Filter the non stored properties
            SqlProperties = props.Where(p => !p.GetCustomAttributes <NotMappedAttribute>().Any()).Select(p => new SqlPropertyMetadata(p)).ToArray();

            // Filter key properties
            KeySqlProperties = props.Where(p => p.GetCustomAttributes <KeyAttribute>().Any()).Select(p => new SqlPropertyMetadata(p)).ToArray();

            // Use identity as key pattern
            var identityProperty = props.FirstOrDefault(p => p.GetCustomAttributes <IdentityAttribute>().Any());

            IdentitySqlProperty = identityProperty != null ? new SqlPropertyMetadata(identityProperty) : null;

            var dateChangedProperty = props.FirstOrDefault(p => p.GetCustomAttributes <UpdatedAtAttribute>().Any());

            if (dateChangedProperty != null && (dateChangedProperty.PropertyType == typeof(DateTime) || dateChangedProperty.PropertyType == typeof(DateTime?)))
            {
                UpdatedAtProperty         = dateChangedProperty;
                UpdatedAtPropertyMetadata = new SqlPropertyMetadata(UpdatedAtProperty);
            }
        }
        private string AppendJoinToSelect(SqlQuery originalBuilder, params Expression <Func <TEntity, object> >[] includes)
        {
            var joinBuilder = new StringBuilder();

            foreach (var include in includes)
            {
                var joinProperty   = AllProperties.First(q => q.Name == ExpressionHelper.GetPropertyName(include));
                var declaringType  = joinProperty.DeclaringType.GetTypeInfo();
                var tableAttribute = declaringType.GetCustomAttribute <TableAttribute>();
                var tableName      = tableAttribute != null ? tableAttribute.Name : declaringType.Name;

                var attrJoin = joinProperty.GetCustomAttribute <JoinAttributeBase>();

                if (attrJoin == null)
                {
                    continue;
                }

                var joinString = "";
                if (attrJoin is LeftJoinAttribute)
                {
                    joinString = "LEFT JOIN";
                }
                else if (attrJoin is InnerJoinAttribute)
                {
                    joinString = "INNER JOIN";
                }
                else if (attrJoin is RightJoinAttribute)
                {
                    joinString = "RIGHT JOIN";
                }

                var joinType   = joinProperty.PropertyType.IsGenericType() ? joinProperty.PropertyType.GenericTypeArguments[0] : joinProperty.PropertyType;
                var properties = joinType.FindClassProperties().Where(ExpressionHelper.GetPrimitivePropertiesPredicate());
                var props      = properties.Where(p => !p.GetCustomAttributes <NotMappedAttribute>().Any()).Select(p => new SqlPropertyMetadata(p)).ToArray();

                if (Config.UseQuotationMarks)
                {
                    switch (Config.SqlProvider)
                    {
                    case SqlProvider.MSSQL:
                        tableName            = "[" + tableName + "]";
                        attrJoin.TableName   = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema, "[", "]");
                        attrJoin.Key         = "[" + attrJoin.Key + "]";
                        attrJoin.ExternalKey = "[" + attrJoin.ExternalKey + "]";
                        attrJoin.TableAlias  = "[" + attrJoin.TableAlias + "]";
                        foreach (var prop in props)
                        {
                            prop.ColumnName = "[" + prop.ColumnName + "]";
                        }
                        break;

                    case SqlProvider.MySQL:
                        tableName            = "`" + tableName + "`";
                        attrJoin.TableName   = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema, "`", "`");
                        attrJoin.Key         = "`" + attrJoin.Key + "`";
                        attrJoin.ExternalKey = "`" + attrJoin.ExternalKey + "`";
                        attrJoin.TableAlias  = "`" + attrJoin.TableAlias + "`";
                        foreach (var prop in props)
                        {
                            prop.ColumnName = "`" + prop.ColumnName + "`";
                        }
                        break;

                    case SqlProvider.PostgreSQL:
                        tableName            = "\"" + tableName + "\"";
                        attrJoin.TableName   = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema, "\"", "\"");
                        attrJoin.Key         = "\"" + attrJoin.Key + "\"";
                        attrJoin.ExternalKey = "\"" + attrJoin.ExternalKey + "\"";
                        attrJoin.TableAlias  = "\"" + attrJoin.TableAlias + "\"";
                        foreach (var prop in props)
                        {
                            prop.ColumnName = "\"" + prop.ColumnName + "\"";
                        }
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(Config.SqlProvider));
                    }
                }
                else
                {
                    attrJoin.TableName = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema);
                }

                originalBuilder.SqlBuilder.Append($", {GetFieldsSelect(attrJoin.TableAlias, props)}");
                joinBuilder.Append(
                    $"{joinString} {attrJoin.TableName} AS {attrJoin.TableAlias} ON {tableName}.{attrJoin.Key} = {attrJoin.TableAlias}.{attrJoin.ExternalKey} ");

                if (LogicalDelete && props.Any(s => s.PropertyName == LogicalDeleteProperty.Name))
                {
                    bool isDateTime = LogicalDeleteProperty.PropertyType.IsDateTime();
                    joinBuilder.AppendFormat(" AND {0}.{1} {2} {3} ", attrJoin.TableAlias, LogicalDeletePropertyMetadata.ColumnName, isDateTime ? "IS" : "!=", isDateTime ? "NULL" : GetLogicalDeleteValue());
                }
            }

            return(joinBuilder.ToString());
        }
Beispiel #6
0
        private string AppendJoinToSelect(SqlQuery originalBuilder, params Expression <Func <TEntity, object> >[] includes)
        {
            var joinBuilder = new StringBuilder();

            foreach (var include in includes)
            {
                var joinProperty   = AllProperties.First(q => q.Name == ExpressionHelper.GetPropertyName(include));
                var declaringType  = joinProperty.DeclaringType.GetTypeInfo();
                var tableAttribute = declaringType.GetCustomAttribute <TableAttribute>();
                var tableName      = tableAttribute != null ? tableAttribute.Name : declaringType.Name;

                var attrJoin = joinProperty.GetCustomAttribute <JoinAttributeBase>();

                if (attrJoin == null)
                {
                    continue;
                }

                var joinString = "";
                if (attrJoin is LeftJoinAttribute)
                {
                    joinString = "LEFT JOIN";
                }
                else if (attrJoin is InnerJoinAttribute)
                {
                    joinString = "INNER JOIN";
                }
                else if (attrJoin is RightJoinAttribute)
                {
                    joinString = "RIGHT JOIN";
                }

                var joinType   = joinProperty.PropertyType.IsGenericType() ? joinProperty.PropertyType.GenericTypeArguments[0] : joinProperty.PropertyType;
                var properties = joinType.FindClassProperties().Where(ExpressionHelper.GetPrimitivePropertiesPredicate());
                var props      = properties.Where(p => !p.GetCustomAttributes <NotMappedAttribute>().Any()).Select(p => new SqlPropertyMetadata(p)).ToArray();

                if (Config.UseQuotationMarks)
                {
                    switch (Config.SqlConnector)
                    {
                    case ESqlConnector.MSSQL:
                        tableName            = "[" + tableName + "]";
                        attrJoin.TableName   = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema, "[", "]");
                        attrJoin.Key         = "[" + attrJoin.Key + "]";
                        attrJoin.ExternalKey = "[" + attrJoin.ExternalKey + "]";
                        foreach (var prop in props)
                        {
                            prop.ColumnName = "[" + prop.ColumnName + "]";
                        }
                        break;

                    case ESqlConnector.MySQL:
                        tableName            = "`" + tableName + "`";
                        attrJoin.TableName   = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema, "`", "`");
                        attrJoin.Key         = "`" + attrJoin.Key + "`";
                        attrJoin.ExternalKey = "`" + attrJoin.ExternalKey + "`";
                        foreach (var prop in props)
                        {
                            prop.ColumnName = "`" + prop.ColumnName + "`";
                        }
                        break;

                    case ESqlConnector.PostgreSQL:
                        tableName            = "\"" + tableName + "\"";
                        attrJoin.TableName   = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema, "\"", "\"");
                        attrJoin.Key         = "\"" + attrJoin.Key + "\"";
                        attrJoin.ExternalKey = "\"" + attrJoin.ExternalKey + "\"";
                        foreach (var prop in props)
                        {
                            prop.ColumnName = "\"" + prop.ColumnName + "\"";
                        }
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(Config.SqlConnector));
                    }
                }
                else
                {
                    attrJoin.TableName = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema);
                }

                originalBuilder.SqlBuilder.Append(", " + GetFieldsSelect(attrJoin.TableName, props));
                joinBuilder.Append(joinString + " " + attrJoin.TableName + " ON " + tableName + "." + attrJoin.Key + " = " + attrJoin.TableName + "." + attrJoin.ExternalKey + " ");
            }
            return(joinBuilder.ToString());
        }
Beispiel #7
0
        public SqlGenerator(ESqlConnector sqlConnector)
        {
            SqlConnector = sqlConnector;
            var entityType     = typeof(TEntity);
            var entityTypeInfo = entityType.GetTypeInfo();
            var aliasAttribute = entityTypeInfo.GetCustomAttribute <TableAttribute>();

            this.TableName = aliasAttribute != null ? aliasAttribute.Name : entityTypeInfo.Name;
            AllProperties  = entityType.GetProperties();
            //Load all the "primitive" entity properties
            var props = AllProperties.Where(ExpressionHelper.GetPrimitivePropertiesPredicate()).ToArray();

            //Filter the non stored properties
            this.BaseProperties = props.Where(p => !p.GetCustomAttributes <NotMappedAttribute>().Any()).Select(p => new PropertyMetadata(p));

            //Filter key properties
            this.KeyProperties = props.Where(p => p.GetCustomAttributes <KeyAttribute>().Any()).Select(p => new PropertyMetadata(p));

            //Use identity as key pattern
            var identityProperty = props.FirstOrDefault(p => p.GetCustomAttributes <IdentityAttribute>().Any());

            this.IdentityProperty = identityProperty != null ? new PropertyMetadata(identityProperty) : null;

            //Status property (if exists, and if it does, it must be an enumeration)
            var statusProperty = props.FirstOrDefault(p => p.GetCustomAttributes <StatusAttribute>().Any());

            if (statusProperty == null)
            {
                return;
            }
            StatusProperty = new PropertyMetadata(statusProperty);

            if (statusProperty.PropertyType.IsBool())
            {
                var deleteProperty = props.FirstOrDefault(p => p.GetCustomAttributes <DeletedAttribute>().Any());
                if (deleteProperty == null)
                {
                    return;
                }

                LogicalDelete      = true;
                LogicalDeleteValue = 1; // true
            }
            else if (statusProperty.PropertyType.IsEnum())
            {
                var deleteOption =
                    statusProperty.PropertyType.GetFields()
                    .FirstOrDefault(f => f.GetCustomAttribute <DeletedAttribute>() != null);

                if (deleteOption == null)
                {
                    return;
                }

                var enumValue = Enum.Parse(statusProperty.PropertyType, deleteOption.Name);

                if (enumValue != null)
                {
                    LogicalDeleteValue = Convert.ChangeType(enumValue, Enum.GetUnderlyingType(statusProperty.PropertyType));
                }

                LogicalDelete = true;
            }
        }
Beispiel #8
0
        private string AppendJoinToSelect(SqlQuery originalBuilder, params Expression <Func <TEntity, object> >[] includes)
        {
            var joinBuilder = new StringBuilder();

            foreach (var include in includes)
            {
                var joinProperty = AllProperties.First(q => q.Name == ExpressionHelper.GetPropertyName(include));
                var attrJoin     = joinProperty.GetCustomAttribute <JoinAttributeBase>();

                if (attrJoin == null)
                {
                    continue;
                }

                var declaringType  = joinProperty.DeclaringType.GetTypeInfo();
                var tableAttribute = declaringType.GetCustomAttribute <TableAttribute>();
                var tableName      = tableAttribute != null ? tableAttribute.Name : declaringType.Name;

                var joinString = "";
                switch (attrJoin)
                {
                case LeftJoinAttribute _:
                    joinString = "LEFT JOIN";
                    break;

                case InnerJoinAttribute _:
                    joinString = "INNER JOIN";
                    break;

                case RightJoinAttribute _ when Config.SqlProvider == SqlProvider.SQLite:
                    throw new NotSupportedException("SQLite doesn't support RIGHT JOIN");

                case RightJoinAttribute _:
                    joinString = "RIGHT JOIN";
                    break;

                case CrossJoinAttribute _:
                    joinString = "CROSS JOIN";
                    break;
                }

                var joinType   = joinProperty.PropertyType.IsGenericType ? joinProperty.PropertyType.GenericTypeArguments[0] : joinProperty.PropertyType;
                var properties = joinType.FindClassProperties().Where(ExpressionHelper.GetPrimitivePropertiesPredicate());
                var props      = properties.Where(p => !p.GetCustomAttributes <NotMappedAttribute>().Any()).Select(p => new SqlPropertyMetadata(p)).ToArray();

                if (Config.UseQuotationMarks)
                {
                    switch (Config.SqlProvider)
                    {
                    case SqlProvider.MSSQL:
                        tableName            = "[" + tableName + "]";
                        attrJoin.TableName   = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema, "[", "]");
                        attrJoin.Key         = "[" + attrJoin.Key + "]";
                        attrJoin.ExternalKey = "[" + attrJoin.ExternalKey + "]";
                        attrJoin.TableAlias  = "[" + attrJoin.TableAlias + "]";
                        foreach (var prop in props)
                        {
                            prop.ColumnName = "[" + prop.ColumnName + "]";
                        }
                        break;

                    case SqlProvider.MySQL:
                        tableName            = "`" + tableName + "`";
                        attrJoin.TableName   = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema, "`", "`");
                        attrJoin.Key         = "`" + attrJoin.Key + "`";
                        attrJoin.ExternalKey = "`" + attrJoin.ExternalKey + "`";
                        attrJoin.TableAlias  = "`" + attrJoin.TableAlias + "`";
                        foreach (var prop in props)
                        {
                            prop.ColumnName = "`" + prop.ColumnName + "`";
                        }
                        break;

                    case SqlProvider.SQLite:
                        break;

                    case SqlProvider.PostgreSQL:
                        tableName            = "\"" + tableName + "\"";
                        attrJoin.TableName   = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema, "\"", "\"");
                        attrJoin.Key         = "\"" + attrJoin.Key + "\"";
                        attrJoin.ExternalKey = "\"" + attrJoin.ExternalKey + "\"";
                        attrJoin.TableAlias  = "\"" + attrJoin.TableAlias + "\"";
                        foreach (var prop in props)
                        {
                            prop.ColumnName = "\"" + prop.ColumnName + "\"";
                        }
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(Config.SqlProvider));
                    }
                }
                else
                {
                    attrJoin.TableName = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema);
                }

                originalBuilder.SqlBuilder.Append($", {GetFieldsSelect(attrJoin.TableAlias, props)}");
                joinBuilder.Append(
                    attrJoin is CrossJoinAttribute
                        ? $"{joinString} {attrJoin.TableName} AS {attrJoin.TableAlias}"
                        : $"{joinString} {attrJoin.TableName} AS {attrJoin.TableAlias} ON {tableName}.{attrJoin.Key} = {attrJoin.TableAlias}.{attrJoin.ExternalKey} ");
            }

            return(joinBuilder.ToString());
        }
Beispiel #9
0
        private void InitProperties()
        {
            var entityType     = typeof(TEntity);
            var entityTypeInfo = entityType.GetTypeInfo();
            var tableAttribute = entityTypeInfo.GetCustomAttribute <TableAttribute>();

            TableName   = tableAttribute != null ? tableAttribute.Name : entityTypeInfo.Name;
            TableSchema = tableAttribute != null ? tableAttribute.Schema : string.Empty;

            AllProperties = entityType.FindClassProperties().Where(q => q.CanWrite).ToArray();

            var props = AllProperties.Where(ExpressionHelper.GetPrimitivePropertiesPredicate()).ToArray();

            var joinProperties = AllProperties.Where(p => p.GetCustomAttributes <JoinAttributeBase>().Any()).ToArray();

            SqlJoinProperties = GetJoinPropertyMetadata(joinProperties);

            // Filter the non stored properties
            SqlProperties = props.Where(p => !p.GetCustomAttributes <NotMappedAttribute>().Any()).Select(p => new SqlPropertyMetadata(p)).ToArray();

            KeyUpsertSqlProperties =
                props.Where(e => e.GetCustomAttributes <UpsertKeyAttribute>().Any())
                .Select(p => new SqlPropertyMetadata(p))
                .ToArray();

            // Filter key properties
            KeySqlProperties = props.Where(p => p.GetCustomAttributes <KeyAttribute>().Any()).Select(p => new SqlPropertyMetadata(p)).ToArray();

            if (!KeySqlProperties.Any())
            {
                var prop = props.SingleOrDefault(p => p.Name.Equals("Id", StringComparison.OrdinalIgnoreCase));
                //skip adding key if prop is null, which means the model doesn't have Id property....
                if (prop != null)
                {
                    KeySqlProperties    = new SqlPropertyMetadata[1];
                    KeySqlProperties[0] = new SqlPropertyMetadata(prop);
                }
            }

            // Use identity as key pattern
            var identityProperty = props.FirstOrDefault(p => p.GetCustomAttributes <IdentityAttribute>().Any());

            IdentitySqlProperty = identityProperty != null ? new SqlPropertyMetadata(identityProperty) : null;

            var dateChangedProperty = props.FirstOrDefault(p => p.GetCustomAttributes <UpdatedAtAttribute>().Count() == 1);

            if (dateChangedProperty != null && (dateChangedProperty.PropertyType == typeof(DateTime) || dateChangedProperty.PropertyType == typeof(DateTime?)))
            {
                UpdatedAtProperty         = props.FirstOrDefault(p => p.GetCustomAttributes <UpdatedAtAttribute>().Any());
                UpdatedAtPropertyMetadata = new SqlPropertyMetadata(UpdatedAtProperty);
            }

            var modifiedDateProperty = props.FirstOrDefault(p => p.GetCustomAttributes <ModifiedAtAttribute>().Count() == 1);

            if (modifiedDateProperty != null &&
                (modifiedDateProperty.PropertyType == typeof(DateTime) ||
                 modifiedDateProperty.PropertyType == typeof(DateTime?)))
            {
                ModifiedAtProperty         = props.FirstOrDefault(p => p.GetCustomAttributes <ModifiedAtAttribute>().Any());
                ModifiedAtPropertyMetadata = new SqlPropertyMetadata(ModifiedAtProperty);
            }
        }
        private string AppendJoinToSelect(SqlQuery originalBuilder, params Expression <Func <TEntity, object> >[] includes)
        {
            var joinSql = "";

            var joinedProperties = new List <PropertyInfo>();

            foreach (var include in includes)
            {
                var propertyName = ExpressionHelper.GetFullPropertyName(include);
                var joinProperty = AllProperties.Concat(joinedProperties).First(x =>
                {
                    if (x.DeclaringType != null)
                    {
                        return(x.DeclaringType.FullName + "." + x.Name == propertyName);
                    }
                    return(false);
                });

                var tableName = GetTableNameOrAlias(joinProperty.DeclaringType);

                var attrJoin = joinProperty.GetCustomAttribute <JoinAttributeBase>();

                if (attrJoin == null)
                {
                    continue;
                }

                var joinString = "";
                if (attrJoin is LeftJoinAttribute)
                {
                    joinString = "LEFT JOIN";
                }
                else if (attrJoin is InnerJoinAttribute)
                {
                    joinString = "INNER JOIN";
                }
                else if (attrJoin is RightJoinAttribute)
                {
                    joinString = "RIGHT JOIN";
                }

                var joinType = joinProperty.PropertyType.IsGenericType() ? joinProperty.PropertyType.GenericTypeArguments[0] : joinProperty.PropertyType;
                joinedProperties.AddRange(joinType.GetProperties().Where(p => !p.GetCustomAttributes <NotMappedAttribute>().Any()));
                var properties = joinType.GetProperties().Where(ExpressionHelper.GetPrimitivePropertiesPredicate());
                var props      = properties.Where(p => !p.GetCustomAttributes <NotMappedAttribute>().Any()).Select(p => new SqlPropertyMetadata(p)).ToArray();

                switch (SqlConnector)
                {
                case ESqlConnector.MSSQL:
                    tableName            = "[" + tableName + "]";
                    attrJoin.TableName   = "[" + attrJoin.TableName + "]";
                    attrJoin.Key         = "[" + attrJoin.Key + "]";
                    attrJoin.ExternalKey = "[" + attrJoin.ExternalKey + "]";
                    foreach (var prop in props)
                    {
                        prop.ColumnName = "[" + prop.ColumnName + "]";
                    }
                    break;

                case ESqlConnector.MySQL:
                    tableName            = "`" + tableName + "`";
                    attrJoin.TableName   = "`" + attrJoin.TableName + "`";
                    attrJoin.Key         = "`" + attrJoin.Key + "`";
                    attrJoin.ExternalKey = "`" + attrJoin.ExternalKey + "`";
                    foreach (var prop in props)
                    {
                        prop.ColumnName = "`" + prop.ColumnName + "`";
                    }
                    break;

                case ESqlConnector.PostgreSQL:
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(SqlConnector));
                }

                originalBuilder.SqlBuilder.Append(", " + GetFieldsSelect(attrJoin.TableName, props));
                joinSql += joinString + " " + attrJoin.TableName + " ON " + tableName + "." + attrJoin.Key + " = " + attrJoin.TableName + "." + attrJoin.ExternalKey + " ";
            }
            return(joinSql);
        }