public TAttr OriginAttribute <TAttr>(string propertyName, OriginAttribute origin, int recursion = 0)
            where TAttr : Attribute
        {
            if (recursion++ > 1000)
            {
                throw new DivideByZeroException("Infinite origin recursion detected!");
            }

            var org            = GetOriginProperty(propertyName);
            var originProperty = org.Item1;

            var attr = originProperty.GetCustomAttribute(typeof(TAttr));

            if (attr != null)
            {
                return((TAttr)attr);
            }

            var originOrigin = originProperty.GetCustomAttribute <OriginAttribute>();

            if (originOrigin != null)
            {
                var originDictionary = GetPropertyDictionary(org.Item2);
                return(originDictionary.OriginAttribute <TAttr>(originProperty.Name, originOrigin));
            }

            return(null);
        }
        public string OriginExpression(string propertyName, OriginAttribute origin,
                                       DialectExpressionSelector expressionSelector, string aliasPrefix, List <Attribute> extraJoins)
        {
            if (aliasPrefix.Length >= 1000)
            {
                throw new DivideByZeroException("Infinite origin recursion detected!");
            }

            var org            = GetOriginProperty(propertyName);
            var originProperty = org.Item1;

            if (aliasPrefix.Length == 0)
            {
                aliasPrefix = origin.Join;
            }
            else
            {
                aliasPrefix = aliasPrefix + "_" + origin.Join;
            }

            var columnAttr = originProperty.GetCustomAttribute <ColumnAttribute>();

            if (columnAttr != null)
            {
                return(aliasPrefix + "." + SqlSyntax.AutoBracket(columnAttr.Name));
            }
            else
            {
                var originDictionary = GetPropertyDictionary(org.Item2);

                var expressionAttr = originProperty.GetCustomAttributes <ExpressionAttribute>();
                if (expressionAttr.Any())
                {
                    var expression = expressionSelector.GetBestMatch(expressionAttr, x => x.Dialect);
                    return(originDictionary.PrefixAliases(expression.Value, aliasPrefix,
                                                          expressionSelector, extraJoins));
                }
                else
                {
                    var originOrigin = originProperty.GetCustomAttribute <OriginAttribute>();
                    if (originOrigin != null)
                    {
                        originDictionary.PrefixAliases(originOrigin.Join + ".Dummy", aliasPrefix, expressionSelector, extraJoins);
                        return(originDictionary.OriginExpression(originProperty.Name, originOrigin, expressionSelector, aliasPrefix, extraJoins));
                    }
                    else
                    {
                        return(aliasPrefix + "." + SqlSyntax.AutoBracket(originProperty.Name));
                    }
                }
            }
        }
        public string OriginDisplayName(string propertyName, OriginAttribute origin, int recursion = 0)
        {
            if (recursion++ > 1000)
            {
                throw new DivideByZeroException("Infinite origin recursion detected!");
            }

            DisplayNameAttribute attr;

            ISqlJoin join;
            string   prefix = "";
            Tuple <string, ForeignKeyAttribute, ISqlJoin> propJoin;

            if (joinPropertyByAlias.TryGetValue(origin.Join, out propJoin))
            {
                if (propJoin.Item3.TitlePrefix != null)
                {
                    prefix = propJoin.Item3.TitlePrefix;
                }
                else
                {
                    attr = propertyByName[propJoin.Item1].GetCustomAttribute <DisplayNameAttribute>();
                    if (attr != null)
                    {
                        prefix = attr.DisplayName;
                    }
                    else
                    {
                        prefix = propJoin.Item1;
                    }
                }
            }
            else if (rowJoinByAlias.TryGetValue(origin.Join, out join) &&
                     join.TitlePrefix != null)
            {
                prefix = join.TitlePrefix.Length > 0 ? join.TitlePrefix + " " : "";
            }

            Func <string, string> addPrefix = s =>
            {
                if (string.IsNullOrEmpty(prefix) || s == prefix || s.StartsWith(prefix + " "))
                {
                    return(s);
                }

                return(prefix + " " + s);
            };

            var org            = GetOriginProperty(propertyName);
            var originProperty = org.Item1;

            attr = originProperty.GetCustomAttribute <DisplayNameAttribute>();
            if (attr != null)
            {
                return(addPrefix(attr.DisplayName));
            }

            var originOrigin = originProperty.GetCustomAttribute <OriginAttribute>();

            if (originOrigin != null)
            {
                var originDictionary = GetPropertyDictionary(org.Item2);
                return(addPrefix(originDictionary.OriginDisplayName(originProperty.Name, originOrigin)));
            }

            return(addPrefix(originProperty.Name));
        }
        private PropertyInfo GetOriginProperty(PropertyInfo property, OriginAttribute origin,
                                               out Type originRowType)
        {
            var joinAlias = origin.Join;
            Tuple <string, ForeignKeyAttribute, ISqlJoin> joinProperty;

            ISqlJoin rowJoin;

            if (joinPropertyByAlias.TryGetValue(joinAlias, out joinProperty))
            {
                var joinPropertyName = joinProperty.Item1;
                var fk = joinProperty.Item2;
                var lj = joinProperty.Item3;
                originRowType = lj.RowType ?? fk.RowType;

                if (originRowType == null)
                {
                    throw new ArgumentOutOfRangeException("origin", String.Format(
                                                              "Property '{0}' on row type '{1}' has a [Origin] attribute, " +
                                                              "but [ForeignKey] and [LeftJoin] attributes on related join " +
                                                              "property '{2}' doesn't use a typeof(SomeRow)!",
                                                              property.Name, rowType.Name, joinPropertyName));
                }
            }
            else if (rowJoinByAlias.TryGetValue(joinAlias, out rowJoin))
            {
                originRowType = rowJoin.RowType;
                if (originRowType == null)
                {
                    throw new ArgumentOutOfRangeException("origin", String.Format(
                                                              "Property '{0}' on row type '{1}' has a [Origin] attribute, " +
                                                              "but related join declaration on row has no RowType!",
                                                              property.Name, rowType.Name, joinAlias));
                }
            }
            else
            {
                throw new ArgumentOutOfRangeException("origin", String.Format(
                                                          "Property '{0}' on row type '{1}' has a [Origin] attribute, " +
                                                          "but declaration of join '{2}' is not found!",
                                                          property.Name, rowType.Name, joinAlias));
            }

            var          originDictionary = GetPropertyDictionary(originRowType);
            string       originPropertyName;
            PropertyInfo originProperty = null;

            if (origin.Property != null)
            {
                originPropertyName = origin.Property;
            }
            else
            {
                var prefix = prefixByAlias[origin.Join];
                if (prefix != null &&
                    prefix.Length > 0 &&
                    property.Name.StartsWith(prefix) &&
                    property.Name.Length > prefix.Length &&
                    originDictionary.propertyByName.TryGetValue(
                        property.Name.Substring(prefix.Length), out originProperty))
                {
                    originPropertyName = originProperty.Name;
                }
                else
                {
                    originPropertyName = property.Name;
                }
            }

            if (originProperty == null &&
                !originDictionary.propertyByName.TryGetValue(originPropertyName, out originProperty))
            {
                throw new ArgumentOutOfRangeException("origin", String.Format(
                                                          "Property '{0}' on row type '{1}' has a [Origin] attribute, " +
                                                          "but its corresponding property '{2}' on row type '{3}' is not found!",
                                                          property.Name, rowType.Name, originPropertyName, originRowType.Name));
            }

            return(originProperty);
        }