diff Source/Templates/BLToolkit.ttinclude @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/Templates/BLToolkit.ttinclude	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,643 @@
+<#@ assembly name="System.Core"    #>
+<#@ assembly name="System.Data"    #>
+<#@ import namespace="System.Collections.Generic" #>
+<#@ import namespace="System.Data" #>
+<#@ import namespace="System.Linq" #>
+<#@ import namespace="System.IO"   #>
+<#
+	AppDomain.CurrentDomain.AssemblyResolve += (_,args) =>
+	{
+		foreach (var a in Assemblies)
+			if (args.Name.ToLower().IndexOf(a.Key.ToLower()) >= 0)
+				return System.Reflection.Assembly.LoadFile(a.Value);
+	
+		if (DataProviderAssembly != null && args.Name.Split(',')[0] == System.IO.Path.GetFileNameWithoutExtension(DataProviderAssembly))
+			return System.Reflection.Assembly.LoadFile(DataProviderAssembly);
+
+		return null;
+	};
+#><#+
+
+static Dictionary<string,string> Assemblies = new Dictionary<string,string>();
+
+static Action<GeneratedTextTransformation,string> WriteComment        = (tt,s) => tt.WriteLine("//{0}", s);
+static Action<GeneratedTextTransformation,string> WriteSummary        = (tt,s) => 
+{
+	if (!string.IsNullOrWhiteSpace(s))
+	{
+		tt.WriteLine("/// <summary>");
+		tt.WriteLine("/// {0}", s);
+		tt.WriteLine("/// </summary>");
+	}
+};
+static Action<GeneratedTextTransformation,string> WriteUsing          = (tt,s) => tt.WriteLine("using {0};", s);
+static Action<GeneratedTextTransformation,string> WriteBeginNamespace = (tt,s) => { tt.WriteLine("namespace {0}", s); tt.WriteLine("{"); };
+static Action<GeneratedTextTransformation>        WriteEndNamespace   =  tt    => tt.WriteLine("}");
+static Action<GeneratedTextTransformation,string,string> WriteBeginClass = (tt,cl,bc) =>
+{
+	tt.Write("public partial class {0}", cl);
+	if (!string.IsNullOrEmpty(bc))
+		tt.Write(" : {0}", bc);
+	tt.WriteLine("");
+	tt.WriteLine("{");
+};
+static Action<GeneratedTextTransformation>        WriteEndClass       =  tt   => tt.WriteLine("}");
+static Func<string,string,string>                 MakeGenericType     = (c,t) => string.Format("{0}<{1}>", c, t);
+static Func<string,string>                        MakeType            = t     => t;
+
+delegate void WriteTablePropertyAction(GeneratedTextTransformation tt, string name, string pname, int maxlen, int maxplen, string desc);
+
+static WriteTablePropertyAction WriteTableProperty = (tt,name,pname,maxlen,maxplen,desc) =>
+{
+	WriteSummary(tt,desc);
+	tt.WriteLine("public Table<{0}>{1} {2}{3} {{ get {{ return this.GetTable<{0}>();{1} }} }}", name, tt.LenDiff(maxlen, name), pname, tt.LenDiff(maxplen, pname));
+};
+static Action<GeneratedTextTransformation,string> WriteAttribute      = (tt,a) => tt.Write("[{0}]", a);
+static Action<GeneratedTextTransformation>        WriteAttributeLine  =  tt    => tt.WriteLine("");
+
+static string ConnectionString;
+static string ConnectionType;
+static string DataProviderAssembly = null;
+
+string DatabaseName             = null;
+string DataContextName          = null;
+string Namespace                = "DataModel";
+string BaseDataContextClass     = "DbManager";
+string BaseEntityClass          = null;
+string OneToManyAssociationType = "IEnumerable<{0}>";
+
+string OwnerToInclude           = null;
+string[] DatabaseQuote          = null;
+
+bool   RenderField              = false;
+bool   RenderBackReferences     = true;
+bool   RenderForeignKeys        = true;
+
+bool   IsMetadataLoaded;
+
+int MaxColumnTypeLen;
+int MaxColumnMemberLen;
+
+static Action<GeneratedTextTransformation,Column,int[],string[]> RenderColumn = (tt,c,maxLens,attrs) =>
+{
+	WriteSummary(tt,c.Description);
+	
+	if (maxLens.Sum() > 0)
+	{
+		if (attrs.Any(_ => _ != null))
+		{
+			tt.Write("[");
+
+			for (var i = 0; i < attrs.Length; i++)
+			{
+				if (attrs[i] != null)
+				{
+					tt.Write(attrs[i]);
+					tt.WriteSpace(maxLens[i] - attrs[i].Length);
+
+					if (attrs.Skip(i + 1).Any(_ => _ != null))
+						tt.Write(", ");
+					else if (maxLens.Skip(i + 1).Any(_ => _ > 0))
+						tt.WriteSpace(2);
+				}
+				else if (maxLens[i] > 0)
+				{
+					tt.WriteSpace(maxLens[i]);
+					
+					if (maxLens.Skip(i + 1).Any(_ => _ > 0))
+						tt.WriteSpace(2);
+				}
+			}
+
+			tt.Write("] ");
+		}
+		else
+		{
+			tt.WriteSpace(maxLens.Sum() + (maxLens.Where(_ => _ > 0).Count() - 1) * 2 + 3);
+		}
+	}
+
+	tt.Write("public {0}{1} {2}", c.Type, tt.LenDiff(tt.MaxColumnTypeLen, c.Type), c.MemberName);
+
+	if (tt.RenderField)
+	{
+		tt.Write(";");
+		if (c.ColumnType != null)
+			tt.Write(tt.LenDiff(tt.MaxColumnMemberLen, c.MemberName));
+	}
+	else
+		tt.Write("{0} {{ get; set; }}", tt.LenDiff(tt.MaxColumnMemberLen, c.MemberName));
+
+	if (c.ColumnType != null)
+	{
+		tt.Write(" // {0}", c.ColumnType);
+		
+		if (c.Length != 0)
+			tt.Write("({0})", c.Length);
+
+		if (c.Precision != 0)
+		{
+			if (c.Scale == 0)
+				tt.Write("({0})", c.Precision);
+			else
+				tt.Write("({0},{1})", c.Precision, c.Scale);
+		}
+	}
+
+	tt.WriteLine("");
+};
+
+static Action<GeneratedTextTransformation,ForeignKey> RenderForeignKey = (tt,key) =>
+{
+	WriteComment(tt, " " + key.KeyName);
+	tt.WriteLine("[Association(ThisKey=\"{0}\", OtherKey=\"{1}\", CanBeNull={2})]",
+		string.Join(", ", (from c in key.ThisColumns  select c.MemberName).ToArray()),
+		string.Join(", ", (from c in key.OtherColumns select c.MemberName).ToArray()),
+		key.CanBeNull ? "true" : "false");
+
+	if (key.Attributes.Count > 0)
+	{
+		WriteAttribute(tt, string.Join(", ", key.Attributes.Distinct().ToArray()));
+		WriteAttributeLine(tt);
+	}
+
+	tt.Write("public ");
+
+	if (key.AssociationType == AssociationType.OneToMany)
+		tt.Write(tt.OneToManyAssociationType, key.OtherTable.ClassName);
+	else
+		tt.Write(key.OtherTable.ClassName);
+
+	tt.Write(" ");
+	tt.Write(key.MemberName);
+
+	if (tt.RenderField)
+		tt.WriteLine(";");
+	else
+		tt.WriteLine(" { get; set; }");
+};
+
+static Action<GeneratedTextTransformation,Table, bool> RenderTable = (tt,t, renderForeignKeys) =>
+{
+	WriteSummary(tt,t.Description);
+
+	if (t.IsView)
+	{
+		WriteComment(tt, " View");
+	}
+
+	RenderTableAttributes(tt, t);
+
+	WriteBeginClass(tt, t.ClassName, t.BaseClassName);
+	
+	tt.PushIndent("\t");
+
+	if (t.Columns.Count > 0)
+	{
+		tt.MaxColumnTypeLen   = t.Columns.Values.Max(_ => _.Type.Length);
+		tt.MaxColumnMemberLen = t.Columns.Values.Max(_ => _.MemberName.Length);
+
+		var maxLens = new int[]
+		{
+			t.Columns.Values.Max(_ => _.MemberName == _.ColumnName ? 0 : "MapField('')".Length + _.ColumnName.Length),
+			t.Columns.Values.Max(_ => _.IsNullable                 ? "Nullable".Length : _.IsIdentity ? "Identity".Length : 0),
+			t.Columns.Values.Max(_ => _.IsIdentity && _.IsNullable ? "Identity".Length : 0),
+			t.Columns.Values.Max(_ => _.IsPrimaryKey               ? string.Format("PrimaryKey({0})", _.PKIndex).Length : 0),
+			t.Columns.Values.Max(_ => _.Attributes.Count == 0      ? 0 : string.Join(", ", _.Attributes.Distinct().ToArray()).Length),
+		};
+
+		foreach (var c in from c in t.Columns.Values orderby c.ID select c)
+		{
+			var attrs = new string[]
+			{
+				c.MemberName == c.ColumnName ? null : string.Format("MapField(\"{0}\")", c.ColumnName),
+				c.IsNullable                 ? "Nullable" : c.IsIdentity ? "Identity" : null,
+				c.IsIdentity && c.IsNullable ? "Identity" : null,
+				c.IsPrimaryKey               ? string.Format("PrimaryKey({0})", c.PKIndex) : null,
+				c.Attributes.Count == 0      ? null : string.Join(", ", c.Attributes.Distinct().ToArray()),
+			};
+
+			RenderColumn(tt, c, maxLens, attrs);
+		}
+	}
+
+	if (renderForeignKeys && t.ForeignKeys.Count > 0)
+	{
+		foreach (var key in t.ForeignKeys.Values.Where(k => tt.RenderBackReferences || k.BackReference != null))
+		{
+			tt.WriteLine("");
+			RenderForeignKey(tt, key);
+		}
+	}
+
+	tt.PopIndent();
+	WriteEndClass(tt);
+};
+
+static Action<GeneratedTextTransformation,Table> RenderTableAttributes = (tt,t) =>
+{
+	if (t.Attributes.Count > 0)
+	{
+		WriteAttribute(tt, string.Join(", ", t.Attributes.Distinct().ToArray()));
+		WriteAttributeLine(tt);
+	}
+
+	string tbl = "TableName(";
+
+	if (!string.IsNullOrEmpty(tt.DatabaseName))
+		tbl += string.Format("Database=\"{0}\", ", tt.DatabaseName);
+
+	if (!string.IsNullOrEmpty(t.Owner))
+		tbl += string.Format("Owner=\"{0}\", ", t.Owner);
+
+	tbl += string.Format("Name=\"{0}\")", t.TableName);
+
+	WriteAttribute(tt, tbl);
+	WriteAttributeLine(tt);
+};
+
+List<string> Usings = new List<string>()
+{
+	"System",
+	"BLToolkit.Data",
+	"BLToolkit.Data.Linq",
+	"BLToolkit.DataAccess",
+	"BLToolkit.Mapping",
+};
+
+static Action<GeneratedTextTransformation> RenderUsing = tt =>
+{
+	var q =
+		from ns in tt.Usings.Distinct()
+		group ns by ns.Split('.')[0];
+
+	var groups =
+		(from ns in q where ns.Key == "System"                select ns).Concat
+		(from ns in q where ns.Key != "System" orderby ns.Key select ns);
+
+	foreach (var gr in groups)
+	{
+		foreach (var ns in from s in gr orderby s select s)
+			WriteUsing(tt, ns);
+
+		tt.WriteLine("");
+	}
+};
+
+Action<GeneratedTextTransformation> BeforeGenerateModel = _ => {};
+Action<GeneratedTextTransformation> AfterGenerateModel  = _ => {};
+
+Action<GeneratedTextTransformation> BeforeWriteTableProperty = _ => {};
+Action<GeneratedTextTransformation> AfterWriteTableProperty  = _ => {};
+
+void GenerateModel()
+{
+	if (ConnectionString != null) ConnectionString = ConnectionString.Trim();
+	if (DataContextName  != null) DataContextName  = DataContextName. Trim();
+
+	if (string.IsNullOrEmpty(ConnectionString)) { Error("ConnectionString cannot be empty."); return; }
+
+	if (string.IsNullOrEmpty(DataContextName))
+		DataContextName = "DataContext";
+
+	LoadMetadata();
+
+	BeforeGenerateModel(this);
+
+	WriteComment(this, "---------------------------------------------------------------------------------------------------");
+	WriteComment(this, " <auto-generated>");
+	WriteComment(this, "    This code was generated by BLToolkit template for T4.");
+	WriteComment(this, "    Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.");
+	WriteComment(this, " </auto-generated>");
+	WriteComment(this, "---------------------------------------------------------------------------------------------------");
+
+	RenderUsing(this);
+
+	WriteBeginNamespace(this, Namespace);
+	PushIndent("\t");
+
+	WriteBeginClass(this, DataContextName, BaseDataContextClass);
+
+	var tlist   = (from t in Tables.Values orderby t.TableName select t).ToList();
+	var maxlen  = tlist.Max(_ => _.ClassName.Length);
+	var maxplen = tlist.Max(_ => (_.DataContextPropertyName ?? _.ClassName).Length);
+
+	PushIndent("\t");
+
+	BeforeWriteTableProperty(this);
+
+	foreach (var t in tlist)
+		WriteTableProperty(this, t.ClassName, t.DataContextPropertyName ?? t.ClassName, maxlen, maxplen, t.Description);
+
+	AfterWriteTableProperty(this);
+
+	PopIndent();
+
+	WriteEndClass(this);
+
+	foreach (var t in tlist)
+	{
+		WriteLine("");
+		RenderTable(this, t, RenderForeignKeys);
+	}
+
+	PopIndent();
+	WriteEndNamespace(this);
+
+	AfterGenerateModel(this);
+}
+
+string LenDiff(int max, string str)
+{
+	var s = "";
+
+	while (max-- > str.Length)
+		s += " ";
+
+	return s;
+}
+
+void WriteSpace(int len)
+{
+	while (len-- > 0)
+		Write(" ");
+}
+
+List<T> CreateList<T>(T item)
+{
+	return new List<T>();
+}
+
+Func<System.Data.IDbConnection> GetConnectionObject = () =>
+{
+	Type connType = null;
+
+	if (DataProviderAssembly != null)
+	{
+		try
+		{
+			var assembly = System.Reflection.Assembly.LoadFile(DataProviderAssembly);
+			connType = assembly.GetType(ConnectionType) 
+				?? assembly.GetType(ConnectionType.Substring(0, ConnectionType.IndexOf(",")));
+		}
+		catch
+		{
+		}
+	}
+
+	if (connType == null)
+		connType = Type.GetType(ConnectionType);
+
+	return (System.Data.IDbConnection)Activator.CreateInstance(connType);
+};
+
+System.Data.IDbConnection GetConnection()
+{
+	var conn = GetConnectionObject();
+
+	conn.ConnectionString = ConnectionString;
+	conn.Open();
+
+	return conn;
+}
+
+void LoadMetadata()
+{
+	if (IsMetadataLoaded)
+		return;
+
+	IsMetadataLoaded = true;
+
+	if (!string.IsNullOrEmpty(DataProviderAssembly) && !DataProviderAssembly.Contains(":") && DataProviderAssembly.Contains(".."))
+	{
+		try
+		{
+			string path = this.Host.ResolvePath("");
+			DataProviderAssembly = Path.GetFullPath(Path.Combine(path, DataProviderAssembly));
+		}
+		catch 
+		{
+		}
+	}
+
+	BeforeLoadMetadata(this);
+	LoadServerMetadata();
+
+	if (DatabaseQuote != null)
+	{
+		foreach (var t in Tables.Values)
+		{
+			t.TableName = string.Format("{1}{0}{2}", t.TableName, DatabaseQuote.FirstOrDefault(), DatabaseQuote.Skip(1).FirstOrDefault() ?? DatabaseQuote.FirstOrDefault());
+			foreach (var c in t.Columns.Values)
+			{
+				c.ColumnName = string.Format("{1}{0}{2}", c.ColumnName, DatabaseQuote.FirstOrDefault(), DatabaseQuote.Skip(1).FirstOrDefault() ?? DatabaseQuote.FirstOrDefault());
+			}
+		}
+	}
+
+	foreach (var t in Tables.Values)
+	{
+		if (t.ClassName.Contains(" "))
+		{
+			var ss = t.ClassName.Split(' ').Where(_ => _.Trim().Length > 0).Select(_ => char.ToUpper(_[0]) + _.Substring(1));
+			t.ClassName = string.Join("", ss.ToArray());
+		}
+	}
+
+	foreach (var t in Tables.Values)
+		foreach (var key in t.ForeignKeys.Values.ToList())
+			if (!key.KeyName.EndsWith("_BackReference"))
+				key.OtherTable.ForeignKeys.Add(key.KeyName + "_BackReference", key.BackReference = new ForeignKey
+				{
+					KeyName         = key.KeyName    + "_BackReference",
+					MemberName      = key.MemberName + "_BackReference",
+					AssociationType = AssociationType.Auto,
+					OtherTable      = t,
+					ThisColumns     = key.OtherColumns,
+					OtherColumns    = key.ThisColumns,
+				});
+
+	foreach (var t in Tables.Values)
+	{
+		foreach (var key in t.ForeignKeys.Values)
+		{
+			if (key.BackReference != null && key.AssociationType == AssociationType.Auto)
+			{
+				if (key.ThisColumns.All(_ => _.IsPrimaryKey))
+				{
+					if (t.Columns.Values.Count(_ => _.IsPrimaryKey) == key.ThisColumns.Count)
+						key.AssociationType = AssociationType.OneToOne;
+					else
+						key.AssociationType = AssociationType.ManyToOne;
+				}
+				else
+					key.AssociationType = AssociationType.ManyToOne;
+
+				key.CanBeNull = key.ThisColumns.All(_ => _.IsNullable);
+			}
+		}
+	}
+
+	foreach (var t in Tables.Values)
+	{
+		foreach (var key in t.ForeignKeys.Values)
+		{
+			var name = key.MemberName;
+
+			if (key.BackReference != null && key.ThisColumns.Count == 1 && key.ThisColumns[0].MemberName.ToLower().EndsWith("id"))
+			{
+				name = key.ThisColumns[0].MemberName;
+				name = name.Substring(0, name.Length - "id".Length);
+
+				if (!t.ForeignKeys.Values.Select(_ => _.MemberName).Concat(
+					 t.Columns.    Values.Select(_ => _.MemberName)).Concat(
+					 new[] { t.ClassName }).Any(_ => _ == name))
+				{
+					name = key.MemberName;;
+				}
+			}
+			
+			if (name == key.MemberName)
+			{
+				if (name.StartsWith("FK_"))
+					name = name.Substring(3);
+
+				if (name.EndsWith("_BackReference"))
+					name = name.Substring(0, name.Length - "_BackReference".Length);
+
+				name = string.Join("", name.Split('_').Where(_ => _.Length > 0 && _ != t.TableName).ToArray());
+
+				if (name.Length > 0)
+					name = key.AssociationType == AssociationType.OneToMany ? PluralizeAssociationName(name) : SingularizeAssociationName(name);
+			}
+
+			if (name.Length != 0 &&
+				!t.ForeignKeys.Values.Select(_ => _.MemberName).Concat(
+				 t.Columns.    Values.Select(_ => _.MemberName)).Concat(
+				 new[] { t.ClassName }).Any(_ => _ == name))
+			{
+				key.MemberName = name;
+			}
+		}
+	}
+
+	if (Tables.Values.SelectMany(_ => _.ForeignKeys.Values).Any(_ => _.AssociationType == AssociationType.OneToMany))
+		Usings.Add("System.Collections.Generic");
+
+	var keyWords = new HashSet<string>
+	{
+		"abstract", "as",       "base",     "bool",    "break",     "byte",     "case",       "catch",     "char",    "checked",
+		"class",    "const",    "continue", "decimal", "default",   "delegate", "do",         "double",    "else",    "enum",
+		"event",    "explicit", "extern",   "false",   "finally",   "fixed",    "float",      "for",       "foreach", "goto",
+		"if",       "implicit", "in",       "int",     "interface", "internal", "is",         "lock",      "long",    "new",
+		"null",     "object",   "operator", "out",     "override",  "params",   "private",    "protected", "public",  "readonly",
+		"ref",      "return",   "sbyte",    "sealed",  "short",     "sizeof",   "stackalloc", "static",    "struct",  "switch",
+		"this",     "throw",    "true",     "try",     "typeof",    "uint",     "ulong",      "unchecked", "unsafe",  "ushort",
+		"using",    "virtual",  "volatile", "void",    "while"
+	};
+
+	foreach (var t in Tables.Values)
+	{
+		if (keyWords.Contains(t.ClassName))
+			t.ClassName = "@" + t.ClassName;
+
+		if (keyWords.Contains(t.DataContextPropertyName))
+			t.DataContextPropertyName = "@" + t.DataContextPropertyName;
+
+		foreach (var col in t.Columns.Values)
+			if (keyWords.Contains(col.MemberName))
+				col.MemberName = "@" + col.MemberName;
+	}
+
+
+	AfterLoadMetadata(this);
+}
+
+Func<string,string> PluralizeAssociationName   = _ => _ + "s";
+Func<string,string> SingularizeAssociationName = _ => _;
+
+Action<GeneratedTextTransformation> BeforeLoadMetadata = _ => {};
+Action<GeneratedTextTransformation> AfterLoadMetadata  = _ => {};
+
+Dictionary<string,Table> Tables = new Dictionary<string,Table>();
+
+public partial class Table
+{
+	public string       Owner;
+	public string       TableName;
+	public string       ClassName;
+	public string       DataContextPropertyName;
+	public string       BaseClassName;
+	public bool         IsView;
+	public string		Description;
+	public List<string> Attributes = new List<string>();
+
+	public Dictionary<string,Column>     Columns     = new Dictionary<string,Column>();
+	public Dictionary<string,ForeignKey> ForeignKeys = new Dictionary<string,ForeignKey>();
+}
+
+public partial class Column
+{
+	public int          ID;
+	public string       ColumnName; // Column name in database
+	public string       MemberName; // Member name of the generated class
+	public bool         IsNullable;
+	public bool         IsIdentity;
+	public string       Type;       // Type of the generated member
+	public string       ColumnType; // Type of the column in database
+	public bool         IsClass;
+	public DbType       DbType;
+	public SqlDbType    SqlDbType;
+	public long         Length;
+	public int          Precision;
+	public int          Scale;
+	public string		Description;
+
+	public int          PKIndex = -1;
+	public List<string> Attributes = new List<string>();
+
+	public bool IsPrimaryKey { get { return PKIndex >= 0; } }
+}
+
+public enum AssociationType
+{
+	Auto,
+	OneToOne,
+	OneToMany,
+	ManyToOne,
+}
+
+public partial class ForeignKey
+{
+	public string       KeyName;
+	public string       MemberName;
+	public Table        OtherTable;
+	public List<Column> ThisColumns  = new List<Column>();
+	public List<Column> OtherColumns = new List<Column>();
+	public List<string> Attributes   = new List<string>();
+	public bool         CanBeNull    = true;
+	public ForeignKey   BackReference;
+
+	private AssociationType _associationType = AssociationType.Auto;
+	public  AssociationType  AssociationType
+	{
+		get { return _associationType; }
+		set
+		{
+			_associationType = value;
+
+			if (BackReference != null)
+			{
+				switch (value)
+				{
+					case AssociationType.Auto      : BackReference.AssociationType = AssociationType.Auto;      break;
+					case AssociationType.OneToOne  : BackReference.AssociationType = AssociationType.OneToOne;  break;
+					case AssociationType.OneToMany : BackReference.AssociationType = AssociationType.ManyToOne; break;
+					case AssociationType.ManyToOne : BackReference.AssociationType = AssociationType.OneToMany; break;
+				}
+			}
+		}
+	}
+}
+
+#>