public QueryPlan GetQuery(string type, string[] paths, string[] includes = null)
        {
            var typeMapping = _metaInfoProvider.GetTypeMapping(type);
            var tables = typeMapping.Tables.OfType<EntityTable>().ToList();
            var mainTable = tables.First();
            var mainTableContext = GetTableContext(mainTable, "M");
            var selectParts = new List<SelectPart>();
            var selectBuilder = new SelectSqlBuilder(mainTableContext).SelectAll(mainTableContext);
            var mainPart = new TypePart
            {
                Type =  typeMapping,
                Tables = new List<Table>(tables)
            };
            selectParts.Add(mainPart);
            if (includes != null)
            {
                foreach (var include in includes)
                {
                    selectParts.AddRange(Include(selectBuilder, mainTableContext, typeMapping, include));
                }
            }
            foreach (var table in tables.Skip(1))
            {
                var secondContext = GetTableContext(table, "T");
                selectBuilder
                    .SelectAll(secondContext)
                    .InnerJoin(mainTableContext, secondContext, table.IdentityColumn.ColumnName, table.IdentityColumn.ColumnName);
            }
            foreach (var s in paths)
            {
                BuildSelectPredicate(selectBuilder, mainTableContext, typeMapping, s);
            }

            var selectClause = new SelectClause{ Parts = selectParts.ToArray() };
            return new QueryPlan
            {
                SqlString = selectBuilder.GetSql(),
                SelectClause = selectClause
            };
        }
        private IEnumerable<SelectPart> Include(SelectSqlBuilder bulder, TableContext mainTableContext, TypeMappingInfo typeMapping, string include)
        {
            var fields = include.Split('.');
            var currentType = typeMapping;
            var context = mainTableContext;
            foreach (var navigationField in fields)
            {
                var navProperty = (NavigationPropertyMapping) currentType.GetProperty(navigationField);
                if (navProperty.Table is PrimitiveListTable)
                {
                    var listContext = GetTableContext(navProperty.Table, "S");
                    bulder.SelectAll(listContext);
                    bulder.LeftOuterJoin(context, listContext, ((EntityTable)context.Table).IdentityColumn.ColumnName, navProperty.Table.Columns.First().ColumnName);
                    yield return new ExpansionPart
                    {
                        Table = navProperty.Table,
                        CollectingType = currentType,
                        CollectingProperty = navProperty
                    };
                    break;
                }

                //todo: no primitive collections totally and no inheritance lookup
                var targetType = navProperty.TargetType;
                var tableInfo = targetType.Tables.OfType<EntityTable>().First();
                var nextcontext = GetTableContext(tableInfo, "S");
                bulder.SelectAll(nextcontext);

                if (navProperty.Host == ReferenceHost.Parent)
                {
                    bulder.LeftOuterJoin(context, nextcontext, navProperty.ColumnName, tableInfo.IdentityColumn.ColumnName);
                }
                else if (navProperty.Host == ReferenceHost.Child)
                {
                    bulder.LeftOuterJoin(context, nextcontext, ((EntityTable)context.Table).IdentityColumn.ColumnName, navProperty.ColumnName);
                }
                else
                    throw new NotImplementedException();
                yield return new SubTypePart
                {
                    Type = targetType,
                    Tables = new[] {tableInfo},
                    CollectingType = currentType,
                    CollectingProperty = navProperty
                };
                currentType = targetType;
                context = nextcontext;
            }
        }
 private string PredicateForPrimitiveList(SelectSqlBuilder builder, Table tbl, TableContext context)
 {
     var listContext = GetTableContext(tbl, "T");
     builder.InnerJoin(context, listContext, ((EntityTable) context.Table).IdentityColumn.ColumnName,
         tbl.Columns[0].ColumnName);
     return builder.GetEquality(listContext, tbl.Columns[1].ColumnName, builder.GetNextParameter());
 }
        private void BuildSelectPredicate(SelectSqlBuilder builder, TableContext initialContext, TypeMappingInfo type, string s)
        {
            var fields = s.Split('.');
            var currentType = type;
            var context = initialContext;
            string predicate;
            foreach (var navigationField in fields.Take(fields.Length - 1))
            {
                var navProperty = (NavigationPropertyMapping) type.GetProperty(navigationField);
                var table = navProperty.Table;
                if (table is PrimitiveListTable)
                {
                    builder.Where(PredicateForPrimitiveList(builder, table, context));
                    return;
                }
                currentType = navProperty.TargetType;
                //todo: no primitive collections totally and no inheritance lookup
                var tableInfo = currentType.Tables.OfType<EntityTable>().First();
                var nextcontext = GetTableContext(tableInfo, "T");
                if (navProperty.Host == ReferenceHost.Parent)
                {
                    builder.InnerJoin(context, nextcontext, navProperty.ColumnName, tableInfo.IdentityColumn.ColumnName);
                }
                else if (navProperty.Host == ReferenceHost.Child)
                {
                    builder.InnerJoin(context, nextcontext, ((EntityTable)context.Table).IdentityColumn.ColumnName, navProperty.ColumnName);
                }
                else
                    throw new NotImplementedException();

                context = nextcontext;
            }
            var property = currentType.GetProperty(fields.Last());
            var tbl = property.Table;
            if (tbl is PrimitiveListTable)
            {
                predicate = PredicateForPrimitiveList(builder, tbl, context);
            }
            else
            {
                predicate = builder.GetEquality(GetTableContext(tbl, tbl == initialContext.Table ? "M" : "T"), property.ColumnName, builder.GetNextParameter());
            }
            //todo: think of context and inheritance
            builder.Where(predicate);
        }