public static async Task <String> Create(JsonSchema4 schema, Dictionary <String, JsonSchema4> others, String ns)
        {
            bool hasBase = false;

            var baseModelWriter = new BaseModelWriter("Input", CreatePropertyAttributes());
            var baseClass       = ModelTypeGenerator.Create(schema, schema.GetPluralName(), baseModelWriter, ns, ns + ".InputModels", allowPropertyCallback: p =>
            {
                if (p.CreateInputModel())
                {
                    hasBase = hasBase | p.IsAbstractOnInputModel();
                    return(p.IsAbstractOnInputModel());
                }
                return(false);
            });

            var modelWriter = new MainModelWriter(hasBase ? baseClass : null, "Input", CreatePropertyAttributes(), CreateClassAttributes(), false, false,
                                                  a =>
            {
                var interfaces = new String[] { a.BaseClassName, }
                .Concat(a.Writer.GetAdditionalInterfaces());

                a.Builder.AppendLine(
                    $@"    public partial class {a.Name}{a.ModelSuffix}{InterfaceListBuilder.Build(interfaces)}
    {{"
                    );
            })
            {
                AdditionalUsings = $@"using Threax.AspNetCore.Halcyon.Ext.ValueProviders;"
                                   + schema.GetExtraNamespaces(StrConstants.FileNewline)
            };

            return(ModelTypeGenerator.Create(schema, schema.GetPluralName(), modelWriter, ns, ns + ".InputModels",
                                             allowPropertyCallback: AllowProperty,
                                             additionalProperties: await AdditionalProperties(schema, others)));
        }
        public static String Get(JsonSchema4 schema, String ns, bool generated)
        {
            bool hasBase = false;

            var baseWriter = new QueryBaseModelWriter("Query", QueryPropertiesWriter.CreateAttributeBuilder())
            {
                InheritFrom = new String[] { "PagedCollectionQuery" }
            };
            var baseClass = ModelTypeGenerator.Create(schema, schema.GetPluralName(), baseWriter, ns, ns + ".Database", allowPropertyCallback: p =>
            {
                if (p.IsQueryable())
                {
                    hasBase = hasBase | p.IsAbstractOnQuery();
                    return(p.IsAbstractOnQuery());
                }
                return(false);
            });

            var baseClassName = "PagedCollectionQuery";

            if (hasBase)
            {
                baseClassName = $"{BaseModelWriter.CreateBaseClassName(schema.Title, "Query")}";
                baseClass     = $@"
{baseClass}
";
            }
            else
            {
                baseClass = "";
            }

            String Model, model;

            NameGenerator.CreatePascalAndCamel(schema.Title, out Model, out model);
            String Models, models;

            NameGenerator.CreatePascalAndCamel(schema.GetPluralName(), out Models, out models);
            String queryProps = ModelTypeGenerator.Create(schema, schema.GetPluralName(), new QueryPropertiesWriter(), schema, ns, ns, allowPropertyCallback: p =>
            {
                return(p.IsQueryable() && !p.IsAbstractOnQuery());
            });
            String queryCreate = ModelTypeGenerator.Create(schema, schema.GetPluralName(), new QueryCreateWriter(), schema, ns, ns, allowPropertyCallback: p =>
            {
                return(p.IsQueryable());
            });

            return(Create(ns, Model, model, Models, models, queryProps, queryCreate, schema.GetKeyType().GetTypeAsNullable(), baseClass, baseClassName, NameGenerator.CreatePascal(schema.GetKeyName()), schema.GetExtraNamespaces(StrConstants.FileNewline), generated));
        }
        public void SimplestModel()
        {
            var model = PersistentModel.Compile(@"
class a prototype=dbtable
");
            var code  = new BaseModelWriter(model)
            {
                WithHeader = false
            }.ToString();

            Console.WriteLine(code.Replace("\"", "\"\""));
            Assert.AreEqual(@"
using System;
#if !NOQORPENT
using Qorpent.Data;
#endif
namespace Orm.Adapters {
	///<summary>Model for Orm definition</summary>
	public partial class Model {
		///<summary>Retrieve data adapter by type (generic)</summary>
#if NOQORPENT
		public static object GetAdapter<T>(){
			return GetAdapter(typeof(T));
#else
		public static IObjectDataAdapter<T> GetAdapter<T>() where T:class,new(){
			return (IObjectDataAdapter<T>)GetAdapter(typeof(T));
#endif
		}
		///<summary>Retrieve data adapter by type</summary>
#if NOQORPENT
		public static object GetAdapter(Type objectType){
#else
		public static IObjectDataAdapter GetAdapter(Type objectType){
#endif
			switch(objectType.Name){
				case ""a"": return new aDataAdapter();
			}
			return null;
		}
	}
}

".Trim(), code.Trim());
        }
        public static async Task <String> Create(JsonSchema4 schema, Dictionary <String, JsonSchema4> others, String ns, bool generated)
        {
            bool hasBase = false;

            var baseWriter = new BaseModelWriter("", CreateAttributeBuilder());
            var baseClass  = ModelTypeGenerator.Create(schema, schema.GetPluralName(), baseWriter, ns, ns + ".ViewModels", allowPropertyCallback: p =>
            {
                if (p.CreateViewModel())
                {
                    hasBase = hasBase | p.IsAbstractOnViewModel();
                    return(p.IsAbstractOnViewModel());
                }
                return(false);
            });

            var mainWriter = new MainModelWriter(hasBase ? baseClass : null, "", CreateAttributeBuilder(), new NoAttributeBuilder(), schema.AllowCreated(), schema.AllowModified(),
                                                 a =>
            {
                var interfaces = new String[] { a.BaseClassName, }
                .Concat(a.Writer.GetAdditionalInterfaces());

                if (!generated)
                {
                    a.Builder.AppendLine(GetLinks(schema.GetPluralName()));
                }

                a.Builder.AppendLine(
                    $@"    public partial class {a.Name}{InterfaceListBuilder.Build(interfaces)}
    {{");

                a.Writer.CreateProperty(a.Builder, NameGenerator.CreatePascal(schema.GetKeyName()), new TypeWriterPropertyInfo(schema.GetKeyType()));
            }
                                                 )
            {
                AdditionalUsings =
                    $@"using {ns}.Controllers.Api;
using Threax.AspNetCore.Halcyon.Ext.ValueProviders;"
                    + schema.GetExtraNamespaces(StrConstants.FileNewline)
            };

            return(ModelTypeGenerator.Create(schema, schema.GetPluralName(), mainWriter, ns, ns + ".ViewModels",
                                             allowPropertyCallback: AllowProperty,
                                             additionalProperties: await AdditionalProperties(schema, others)));
        }
        public static String Create(JsonSchema4 schema, Dictionary <String, JsonSchema4> others, String ns)
        {
            bool hasBase = false;

            var baseWriter = new BaseModelWriter("Entity", CreateAttributeBuilder());
            var baseClass  = ModelTypeGenerator.Create(schema, schema.GetPluralName(), baseWriter, ns, ns + ".Database", allowPropertyCallback: p =>
            {
                if (p.CreateEntity())
                {
                    hasBase = hasBase | p.IsAbstractOnEntity();
                    return(p.IsAbstractOnEntity());
                }
                return(false);
            });

            var mainWriter = new MainModelWriter(hasBase ? baseClass : null, "Entity", CreateAttributeBuilder(), new NoAttributeBuilder(), schema.AllowCreated(), schema.AllowModified(),
                                                 a =>
            {
                var interfaces = new String[] { a.BaseClassName, }
                .Concat(a.Writer.GetAdditionalInterfaces());

                a.Builder.AppendLine(
                    $@"    public partial class {a.Name}Entity{InterfaceListBuilder.Build(interfaces)}
    {{
        [Key]"
                    );

                a.Writer.CreateProperty(a.Builder, NameGenerator.CreatePascal(schema.GetKeyName()), new TypeWriterPropertyInfo(schema.GetKeyType()));
            }
                                                 )
            {
                AdditionalUsings = schema.GetExtraNamespaces(StrConstants.FileNewline)
            };

            return(ModelTypeGenerator.Create(schema, schema.GetPluralName(), mainWriter, ns, ns + ".Database",
                                             allowPropertyCallback: AllowProperty,
                                             additionalProperties: AdditionalProperties(schema, others)));
        }
        public void ModelWithReferencesAndAutoAndLazySetup()
        {
            var model = PersistentModel.Compile(@"
class a prototype=dbtable 
class b prototype=dbtable
	ref a reverse auto reverse-lazy
class c prototype=dbtable
	ref b reverse reverse-auto lazy
");
            var code  = new BaseModelWriter(model)
            {
                WithHeader = false
            }.ToString();

            Console.WriteLine(code.Replace("\"", "\"\""));
            Assert.AreEqual(@"
using System;
#if !NOQORPENT
using Qorpent.Data;
#endif
namespace Orm.Adapters {
	///<summary>Model for Orm definition</summary>
	public partial class Model {
		///<summary>Retrieve data adapter by type (generic)</summary>
#if NOQORPENT
		public static object GetAdapter<T>(){
			return GetAdapter(typeof(T));
#else
		public static IObjectDataAdapter<T> GetAdapter<T>() where T:class,new(){
			return (IObjectDataAdapter<T>)GetAdapter(typeof(T));
#endif
		}
		///<summary>Retrieve data adapter by type</summary>
#if NOQORPENT
		public static object GetAdapter(Type objectType){
#else
		public static IObjectDataAdapter GetAdapter(Type objectType){
#endif
			switch(objectType.Name){
				case ""a"": return new aDataAdapter();
				case ""b"": return new bDataAdapter();
				case ""c"": return new cDataAdapter();
			}
			return null;
		}
		///<summary>Marks active auto foreign key link from b to a with Id (reverse)</summary>
		public bool AutoLoadba = true;
		///<summary>Marks active auto foreign key link from b to a with Id (reverse) as LazyLoad </summary>
		public bool Lazyba = false;
		///<summary>Marks active auto collection in b of b with a (reverse)</summary>
		public bool AutoLoadabs=false;
		///<summary>Marks active auto collection in b of b with a (reverse) as Lazy</summary>
		public bool Lazyabs=true;
		///<summary>Marks active auto foreign key link from c to b with Id (reverse)</summary>
		public bool AutoLoadcb = false;
		///<summary>Marks active auto foreign key link from c to b with Id (reverse) as LazyLoad </summary>
		public bool Lazycb = true;
		///<summary>Marks active auto collection in c of c with b (reverse)</summary>
		public bool AutoLoadbcs=true;
		///<summary>Marks active auto collection in c of c with b (reverse) as Lazy</summary>
		public bool Lazybcs=false;
	}
}

".Trim(), code.Trim());
        }