| 0 | 1 <#@ assembly name="System.Core"    #> | 
|  | 2 <#@ assembly name="System.Data"    #> | 
|  | 3 <#@ import namespace="System.Collections.Generic" #> | 
|  | 4 <#@ import namespace="System.Data" #> | 
|  | 5 <#@ import namespace="System.Linq" #> | 
|  | 6 <#@ import namespace="System.IO"   #> | 
|  | 7 <# | 
|  | 8 	AppDomain.CurrentDomain.AssemblyResolve += (_,args) => | 
|  | 9 	{ | 
|  | 10 		foreach (var a in Assemblies) | 
|  | 11 			if (args.Name.ToLower().IndexOf(a.Key.ToLower()) >= 0) | 
|  | 12 				return System.Reflection.Assembly.LoadFile(a.Value); | 
|  | 13 | 
|  | 14 		if (DataProviderAssembly != null && args.Name.Split(',')[0] == System.IO.Path.GetFileNameWithoutExtension(DataProviderAssembly)) | 
|  | 15 			return System.Reflection.Assembly.LoadFile(DataProviderAssembly); | 
|  | 16 | 
|  | 17 		return null; | 
|  | 18 	}; | 
|  | 19 #><#+ | 
|  | 20 | 
|  | 21 static Dictionary<string,string> Assemblies = new Dictionary<string,string>(); | 
|  | 22 | 
|  | 23 static Action<GeneratedTextTransformation,string> WriteComment        = (tt,s) => tt.WriteLine("//{0}", s); | 
|  | 24 static Action<GeneratedTextTransformation,string> WriteSummary        = (tt,s) => | 
|  | 25 { | 
|  | 26 	if (!string.IsNullOrWhiteSpace(s)) | 
|  | 27 	{ | 
|  | 28 		tt.WriteLine("/// <summary>"); | 
|  | 29 		tt.WriteLine("/// {0}", s); | 
|  | 30 		tt.WriteLine("/// </summary>"); | 
|  | 31 	} | 
|  | 32 }; | 
|  | 33 static Action<GeneratedTextTransformation,string> WriteUsing          = (tt,s) => tt.WriteLine("using {0};", s); | 
|  | 34 static Action<GeneratedTextTransformation,string> WriteBeginNamespace = (tt,s) => { tt.WriteLine("namespace {0}", s); tt.WriteLine("{"); }; | 
|  | 35 static Action<GeneratedTextTransformation>        WriteEndNamespace   =  tt    => tt.WriteLine("}"); | 
|  | 36 static Action<GeneratedTextTransformation,string,string> WriteBeginClass = (tt,cl,bc) => | 
|  | 37 { | 
|  | 38 	tt.Write("public partial class {0}", cl); | 
|  | 39 	if (!string.IsNullOrEmpty(bc)) | 
|  | 40 		tt.Write(" : {0}", bc); | 
|  | 41 	tt.WriteLine(""); | 
|  | 42 	tt.WriteLine("{"); | 
|  | 43 }; | 
|  | 44 static Action<GeneratedTextTransformation>        WriteEndClass       =  tt   => tt.WriteLine("}"); | 
|  | 45 static Func<string,string,string>                 MakeGenericType     = (c,t) => string.Format("{0}<{1}>", c, t); | 
|  | 46 static Func<string,string>                        MakeType            = t     => t; | 
|  | 47 | 
|  | 48 delegate void WriteTablePropertyAction(GeneratedTextTransformation tt, string name, string pname, int maxlen, int maxplen, string desc); | 
|  | 49 | 
|  | 50 static WriteTablePropertyAction WriteTableProperty = (tt,name,pname,maxlen,maxplen,desc) => | 
|  | 51 { | 
|  | 52 	WriteSummary(tt,desc); | 
|  | 53 	tt.WriteLine("public Table<{0}>{1} {2}{3} {{ get {{ return this.GetTable<{0}>();{1} }} }}", name, tt.LenDiff(maxlen, name), pname, tt.LenDiff(maxplen, pname)); | 
|  | 54 }; | 
|  | 55 static Action<GeneratedTextTransformation,string> WriteAttribute      = (tt,a) => tt.Write("[{0}]", a); | 
|  | 56 static Action<GeneratedTextTransformation>        WriteAttributeLine  =  tt    => tt.WriteLine(""); | 
|  | 57 | 
|  | 58 static string ConnectionString; | 
|  | 59 static string ConnectionType; | 
|  | 60 static string DataProviderAssembly = null; | 
|  | 61 | 
|  | 62 string DatabaseName             = null; | 
|  | 63 string DataContextName          = null; | 
|  | 64 string Namespace                = "DataModel"; | 
|  | 65 string BaseDataContextClass     = "DbManager"; | 
|  | 66 string BaseEntityClass          = null; | 
|  | 67 string OneToManyAssociationType = "IEnumerable<{0}>"; | 
|  | 68 | 
|  | 69 string OwnerToInclude           = null; | 
|  | 70 string[] DatabaseQuote          = null; | 
|  | 71 | 
|  | 72 bool   RenderField              = false; | 
|  | 73 bool   RenderBackReferences     = true; | 
|  | 74 bool   RenderForeignKeys        = true; | 
|  | 75 | 
|  | 76 bool   IsMetadataLoaded; | 
|  | 77 | 
|  | 78 int MaxColumnTypeLen; | 
|  | 79 int MaxColumnMemberLen; | 
|  | 80 | 
|  | 81 static Action<GeneratedTextTransformation,Column,int[],string[]> RenderColumn = (tt,c,maxLens,attrs) => | 
|  | 82 { | 
|  | 83 	WriteSummary(tt,c.Description); | 
|  | 84 | 
|  | 85 	if (maxLens.Sum() > 0) | 
|  | 86 	{ | 
|  | 87 		if (attrs.Any(_ => _ != null)) | 
|  | 88 		{ | 
|  | 89 			tt.Write("["); | 
|  | 90 | 
|  | 91 			for (var i = 0; i < attrs.Length; i++) | 
|  | 92 			{ | 
|  | 93 				if (attrs[i] != null) | 
|  | 94 				{ | 
|  | 95 					tt.Write(attrs[i]); | 
|  | 96 					tt.WriteSpace(maxLens[i] - attrs[i].Length); | 
|  | 97 | 
|  | 98 					if (attrs.Skip(i + 1).Any(_ => _ != null)) | 
|  | 99 						tt.Write(", "); | 
|  | 100 					else if (maxLens.Skip(i + 1).Any(_ => _ > 0)) | 
|  | 101 						tt.WriteSpace(2); | 
|  | 102 				} | 
|  | 103 				else if (maxLens[i] > 0) | 
|  | 104 				{ | 
|  | 105 					tt.WriteSpace(maxLens[i]); | 
|  | 106 | 
|  | 107 					if (maxLens.Skip(i + 1).Any(_ => _ > 0)) | 
|  | 108 						tt.WriteSpace(2); | 
|  | 109 				} | 
|  | 110 			} | 
|  | 111 | 
|  | 112 			tt.Write("] "); | 
|  | 113 		} | 
|  | 114 		else | 
|  | 115 		{ | 
|  | 116 			tt.WriteSpace(maxLens.Sum() + (maxLens.Where(_ => _ > 0).Count() - 1) * 2 + 3); | 
|  | 117 		} | 
|  | 118 	} | 
|  | 119 | 
|  | 120 	tt.Write("public {0}{1} {2}", c.Type, tt.LenDiff(tt.MaxColumnTypeLen, c.Type), c.MemberName); | 
|  | 121 | 
|  | 122 	if (tt.RenderField) | 
|  | 123 	{ | 
|  | 124 		tt.Write(";"); | 
|  | 125 		if (c.ColumnType != null) | 
|  | 126 			tt.Write(tt.LenDiff(tt.MaxColumnMemberLen, c.MemberName)); | 
|  | 127 	} | 
|  | 128 	else | 
|  | 129 		tt.Write("{0} {{ get; set; }}", tt.LenDiff(tt.MaxColumnMemberLen, c.MemberName)); | 
|  | 130 | 
|  | 131 	if (c.ColumnType != null) | 
|  | 132 	{ | 
|  | 133 		tt.Write(" // {0}", c.ColumnType); | 
|  | 134 | 
|  | 135 		if (c.Length != 0) | 
|  | 136 			tt.Write("({0})", c.Length); | 
|  | 137 | 
|  | 138 		if (c.Precision != 0) | 
|  | 139 		{ | 
|  | 140 			if (c.Scale == 0) | 
|  | 141 				tt.Write("({0})", c.Precision); | 
|  | 142 			else | 
|  | 143 				tt.Write("({0},{1})", c.Precision, c.Scale); | 
|  | 144 		} | 
|  | 145 	} | 
|  | 146 | 
|  | 147 	tt.WriteLine(""); | 
|  | 148 }; | 
|  | 149 | 
|  | 150 static Action<GeneratedTextTransformation,ForeignKey> RenderForeignKey = (tt,key) => | 
|  | 151 { | 
|  | 152 	WriteComment(tt, " " + key.KeyName); | 
|  | 153 	tt.WriteLine("[Association(ThisKey=\"{0}\", OtherKey=\"{1}\", CanBeNull={2})]", | 
|  | 154 		string.Join(", ", (from c in key.ThisColumns  select c.MemberName).ToArray()), | 
|  | 155 		string.Join(", ", (from c in key.OtherColumns select c.MemberName).ToArray()), | 
|  | 156 		key.CanBeNull ? "true" : "false"); | 
|  | 157 | 
|  | 158 	if (key.Attributes.Count > 0) | 
|  | 159 	{ | 
|  | 160 		WriteAttribute(tt, string.Join(", ", key.Attributes.Distinct().ToArray())); | 
|  | 161 		WriteAttributeLine(tt); | 
|  | 162 	} | 
|  | 163 | 
|  | 164 	tt.Write("public "); | 
|  | 165 | 
|  | 166 	if (key.AssociationType == AssociationType.OneToMany) | 
|  | 167 		tt.Write(tt.OneToManyAssociationType, key.OtherTable.ClassName); | 
|  | 168 	else | 
|  | 169 		tt.Write(key.OtherTable.ClassName); | 
|  | 170 | 
|  | 171 	tt.Write(" "); | 
|  | 172 	tt.Write(key.MemberName); | 
|  | 173 | 
|  | 174 	if (tt.RenderField) | 
|  | 175 		tt.WriteLine(";"); | 
|  | 176 	else | 
|  | 177 		tt.WriteLine(" { get; set; }"); | 
|  | 178 }; | 
|  | 179 | 
|  | 180 static Action<GeneratedTextTransformation,Table, bool> RenderTable = (tt,t, renderForeignKeys) => | 
|  | 181 { | 
|  | 182 	WriteSummary(tt,t.Description); | 
|  | 183 | 
|  | 184 	if (t.IsView) | 
|  | 185 	{ | 
|  | 186 		WriteComment(tt, " View"); | 
|  | 187 	} | 
|  | 188 | 
|  | 189 	RenderTableAttributes(tt, t); | 
|  | 190 | 
|  | 191 	WriteBeginClass(tt, t.ClassName, t.BaseClassName); | 
|  | 192 | 
|  | 193 	tt.PushIndent("\t"); | 
|  | 194 | 
|  | 195 	if (t.Columns.Count > 0) | 
|  | 196 	{ | 
|  | 197 		tt.MaxColumnTypeLen   = t.Columns.Values.Max(_ => _.Type.Length); | 
|  | 198 		tt.MaxColumnMemberLen = t.Columns.Values.Max(_ => _.MemberName.Length); | 
|  | 199 | 
|  | 200 		var maxLens = new int[] | 
|  | 201 		{ | 
|  | 202 			t.Columns.Values.Max(_ => _.MemberName == _.ColumnName ? 0 : "MapField('')".Length + _.ColumnName.Length), | 
|  | 203 			t.Columns.Values.Max(_ => _.IsNullable                 ? "Nullable".Length : _.IsIdentity ? "Identity".Length : 0), | 
|  | 204 			t.Columns.Values.Max(_ => _.IsIdentity && _.IsNullable ? "Identity".Length : 0), | 
|  | 205 			t.Columns.Values.Max(_ => _.IsPrimaryKey               ? string.Format("PrimaryKey({0})", _.PKIndex).Length : 0), | 
|  | 206 			t.Columns.Values.Max(_ => _.Attributes.Count == 0      ? 0 : string.Join(", ", _.Attributes.Distinct().ToArray()).Length), | 
|  | 207 		}; | 
|  | 208 | 
|  | 209 		foreach (var c in from c in t.Columns.Values orderby c.ID select c) | 
|  | 210 		{ | 
|  | 211 			var attrs = new string[] | 
|  | 212 			{ | 
|  | 213 				c.MemberName == c.ColumnName ? null : string.Format("MapField(\"{0}\")", c.ColumnName), | 
|  | 214 				c.IsNullable                 ? "Nullable" : c.IsIdentity ? "Identity" : null, | 
|  | 215 				c.IsIdentity && c.IsNullable ? "Identity" : null, | 
|  | 216 				c.IsPrimaryKey               ? string.Format("PrimaryKey({0})", c.PKIndex) : null, | 
|  | 217 				c.Attributes.Count == 0      ? null : string.Join(", ", c.Attributes.Distinct().ToArray()), | 
|  | 218 			}; | 
|  | 219 | 
|  | 220 			RenderColumn(tt, c, maxLens, attrs); | 
|  | 221 		} | 
|  | 222 	} | 
|  | 223 | 
|  | 224 	if (renderForeignKeys && t.ForeignKeys.Count > 0) | 
|  | 225 	{ | 
|  | 226 		foreach (var key in t.ForeignKeys.Values.Where(k => tt.RenderBackReferences || k.BackReference != null)) | 
|  | 227 		{ | 
|  | 228 			tt.WriteLine(""); | 
|  | 229 			RenderForeignKey(tt, key); | 
|  | 230 		} | 
|  | 231 	} | 
|  | 232 | 
|  | 233 	tt.PopIndent(); | 
|  | 234 	WriteEndClass(tt); | 
|  | 235 }; | 
|  | 236 | 
|  | 237 static Action<GeneratedTextTransformation,Table> RenderTableAttributes = (tt,t) => | 
|  | 238 { | 
|  | 239 	if (t.Attributes.Count > 0) | 
|  | 240 	{ | 
|  | 241 		WriteAttribute(tt, string.Join(", ", t.Attributes.Distinct().ToArray())); | 
|  | 242 		WriteAttributeLine(tt); | 
|  | 243 	} | 
|  | 244 | 
|  | 245 	string tbl = "TableName("; | 
|  | 246 | 
|  | 247 	if (!string.IsNullOrEmpty(tt.DatabaseName)) | 
|  | 248 		tbl += string.Format("Database=\"{0}\", ", tt.DatabaseName); | 
|  | 249 | 
|  | 250 	if (!string.IsNullOrEmpty(t.Owner)) | 
|  | 251 		tbl += string.Format("Owner=\"{0}\", ", t.Owner); | 
|  | 252 | 
|  | 253 	tbl += string.Format("Name=\"{0}\")", t.TableName); | 
|  | 254 | 
|  | 255 	WriteAttribute(tt, tbl); | 
|  | 256 	WriteAttributeLine(tt); | 
|  | 257 }; | 
|  | 258 | 
|  | 259 List<string> Usings = new List<string>() | 
|  | 260 { | 
|  | 261 	"System", | 
|  | 262 	"BLToolkit.Data", | 
|  | 263 	"BLToolkit.Data.Linq", | 
|  | 264 	"BLToolkit.DataAccess", | 
|  | 265 	"BLToolkit.Mapping", | 
|  | 266 }; | 
|  | 267 | 
|  | 268 static Action<GeneratedTextTransformation> RenderUsing = tt => | 
|  | 269 { | 
|  | 270 	var q = | 
|  | 271 		from ns in tt.Usings.Distinct() | 
|  | 272 		group ns by ns.Split('.')[0]; | 
|  | 273 | 
|  | 274 	var groups = | 
|  | 275 		(from ns in q where ns.Key == "System"                select ns).Concat | 
|  | 276 		(from ns in q where ns.Key != "System" orderby ns.Key select ns); | 
|  | 277 | 
|  | 278 	foreach (var gr in groups) | 
|  | 279 	{ | 
|  | 280 		foreach (var ns in from s in gr orderby s select s) | 
|  | 281 			WriteUsing(tt, ns); | 
|  | 282 | 
|  | 283 		tt.WriteLine(""); | 
|  | 284 	} | 
|  | 285 }; | 
|  | 286 | 
|  | 287 Action<GeneratedTextTransformation> BeforeGenerateModel = _ => {}; | 
|  | 288 Action<GeneratedTextTransformation> AfterGenerateModel  = _ => {}; | 
|  | 289 | 
|  | 290 Action<GeneratedTextTransformation> BeforeWriteTableProperty = _ => {}; | 
|  | 291 Action<GeneratedTextTransformation> AfterWriteTableProperty  = _ => {}; | 
|  | 292 | 
|  | 293 void GenerateModel() | 
|  | 294 { | 
|  | 295 	if (ConnectionString != null) ConnectionString = ConnectionString.Trim(); | 
|  | 296 	if (DataContextName  != null) DataContextName  = DataContextName. Trim(); | 
|  | 297 | 
|  | 298 	if (string.IsNullOrEmpty(ConnectionString)) { Error("ConnectionString cannot be empty."); return; } | 
|  | 299 | 
|  | 300 	if (string.IsNullOrEmpty(DataContextName)) | 
|  | 301 		DataContextName = "DataContext"; | 
|  | 302 | 
|  | 303 	LoadMetadata(); | 
|  | 304 | 
|  | 305 	BeforeGenerateModel(this); | 
|  | 306 | 
|  | 307 	WriteComment(this, "---------------------------------------------------------------------------------------------------"); | 
|  | 308 	WriteComment(this, " <auto-generated>"); | 
|  | 309 	WriteComment(this, "    This code was generated by BLToolkit template for T4."); | 
|  | 310 	WriteComment(this, "    Changes to this file may cause incorrect behavior and will be lost if the code is regenerated."); | 
|  | 311 	WriteComment(this, " </auto-generated>"); | 
|  | 312 	WriteComment(this, "---------------------------------------------------------------------------------------------------"); | 
|  | 313 | 
|  | 314 	RenderUsing(this); | 
|  | 315 | 
|  | 316 	WriteBeginNamespace(this, Namespace); | 
|  | 317 	PushIndent("\t"); | 
|  | 318 | 
|  | 319 	WriteBeginClass(this, DataContextName, BaseDataContextClass); | 
|  | 320 | 
|  | 321 	var tlist   = (from t in Tables.Values orderby t.TableName select t).ToList(); | 
|  | 322 	var maxlen  = tlist.Max(_ => _.ClassName.Length); | 
|  | 323 	var maxplen = tlist.Max(_ => (_.DataContextPropertyName ?? _.ClassName).Length); | 
|  | 324 | 
|  | 325 	PushIndent("\t"); | 
|  | 326 | 
|  | 327 	BeforeWriteTableProperty(this); | 
|  | 328 | 
|  | 329 	foreach (var t in tlist) | 
|  | 330 		WriteTableProperty(this, t.ClassName, t.DataContextPropertyName ?? t.ClassName, maxlen, maxplen, t.Description); | 
|  | 331 | 
|  | 332 	AfterWriteTableProperty(this); | 
|  | 333 | 
|  | 334 	PopIndent(); | 
|  | 335 | 
|  | 336 	WriteEndClass(this); | 
|  | 337 | 
|  | 338 	foreach (var t in tlist) | 
|  | 339 	{ | 
|  | 340 		WriteLine(""); | 
|  | 341 		RenderTable(this, t, RenderForeignKeys); | 
|  | 342 	} | 
|  | 343 | 
|  | 344 	PopIndent(); | 
|  | 345 	WriteEndNamespace(this); | 
|  | 346 | 
|  | 347 	AfterGenerateModel(this); | 
|  | 348 } | 
|  | 349 | 
|  | 350 string LenDiff(int max, string str) | 
|  | 351 { | 
|  | 352 	var s = ""; | 
|  | 353 | 
|  | 354 	while (max-- > str.Length) | 
|  | 355 		s += " "; | 
|  | 356 | 
|  | 357 	return s; | 
|  | 358 } | 
|  | 359 | 
|  | 360 void WriteSpace(int len) | 
|  | 361 { | 
|  | 362 	while (len-- > 0) | 
|  | 363 		Write(" "); | 
|  | 364 } | 
|  | 365 | 
|  | 366 List<T> CreateList<T>(T item) | 
|  | 367 { | 
|  | 368 	return new List<T>(); | 
|  | 369 } | 
|  | 370 | 
|  | 371 Func<System.Data.IDbConnection> GetConnectionObject = () => | 
|  | 372 { | 
|  | 373 	Type connType = null; | 
|  | 374 | 
|  | 375 	if (DataProviderAssembly != null) | 
|  | 376 	{ | 
|  | 377 		try | 
|  | 378 		{ | 
|  | 379 			var assembly = System.Reflection.Assembly.LoadFile(DataProviderAssembly); | 
|  | 380 			connType = assembly.GetType(ConnectionType) | 
|  | 381 				?? assembly.GetType(ConnectionType.Substring(0, ConnectionType.IndexOf(","))); | 
|  | 382 		} | 
|  | 383 		catch | 
|  | 384 		{ | 
|  | 385 		} | 
|  | 386 	} | 
|  | 387 | 
|  | 388 	if (connType == null) | 
|  | 389 		connType = Type.GetType(ConnectionType); | 
|  | 390 | 
|  | 391 	return (System.Data.IDbConnection)Activator.CreateInstance(connType); | 
|  | 392 }; | 
|  | 393 | 
|  | 394 System.Data.IDbConnection GetConnection() | 
|  | 395 { | 
|  | 396 	var conn = GetConnectionObject(); | 
|  | 397 | 
|  | 398 	conn.ConnectionString = ConnectionString; | 
|  | 399 	conn.Open(); | 
|  | 400 | 
|  | 401 	return conn; | 
|  | 402 } | 
|  | 403 | 
|  | 404 void LoadMetadata() | 
|  | 405 { | 
|  | 406 	if (IsMetadataLoaded) | 
|  | 407 		return; | 
|  | 408 | 
|  | 409 	IsMetadataLoaded = true; | 
|  | 410 | 
|  | 411 	if (!string.IsNullOrEmpty(DataProviderAssembly) && !DataProviderAssembly.Contains(":") && DataProviderAssembly.Contains("..")) | 
|  | 412 	{ | 
|  | 413 		try | 
|  | 414 		{ | 
|  | 415 			string path = this.Host.ResolvePath(""); | 
|  | 416 			DataProviderAssembly = Path.GetFullPath(Path.Combine(path, DataProviderAssembly)); | 
|  | 417 		} | 
|  | 418 		catch | 
|  | 419 		{ | 
|  | 420 		} | 
|  | 421 	} | 
|  | 422 | 
|  | 423 	BeforeLoadMetadata(this); | 
|  | 424 	LoadServerMetadata(); | 
|  | 425 | 
|  | 426 	if (DatabaseQuote != null) | 
|  | 427 	{ | 
|  | 428 		foreach (var t in Tables.Values) | 
|  | 429 		{ | 
|  | 430 			t.TableName = string.Format("{1}{0}{2}", t.TableName, DatabaseQuote.FirstOrDefault(), DatabaseQuote.Skip(1).FirstOrDefault() ?? DatabaseQuote.FirstOrDefault()); | 
|  | 431 			foreach (var c in t.Columns.Values) | 
|  | 432 			{ | 
|  | 433 				c.ColumnName = string.Format("{1}{0}{2}", c.ColumnName, DatabaseQuote.FirstOrDefault(), DatabaseQuote.Skip(1).FirstOrDefault() ?? DatabaseQuote.FirstOrDefault()); | 
|  | 434 			} | 
|  | 435 		} | 
|  | 436 	} | 
|  | 437 | 
|  | 438 	foreach (var t in Tables.Values) | 
|  | 439 	{ | 
|  | 440 		if (t.ClassName.Contains(" ")) | 
|  | 441 		{ | 
|  | 442 			var ss = t.ClassName.Split(' ').Where(_ => _.Trim().Length > 0).Select(_ => char.ToUpper(_[0]) + _.Substring(1)); | 
|  | 443 			t.ClassName = string.Join("", ss.ToArray()); | 
|  | 444 		} | 
|  | 445 	} | 
|  | 446 | 
|  | 447 	foreach (var t in Tables.Values) | 
|  | 448 		foreach (var key in t.ForeignKeys.Values.ToList()) | 
|  | 449 			if (!key.KeyName.EndsWith("_BackReference")) | 
|  | 450 				key.OtherTable.ForeignKeys.Add(key.KeyName + "_BackReference", key.BackReference = new ForeignKey | 
|  | 451 				{ | 
|  | 452 					KeyName         = key.KeyName    + "_BackReference", | 
|  | 453 					MemberName      = key.MemberName + "_BackReference", | 
|  | 454 					AssociationType = AssociationType.Auto, | 
|  | 455 					OtherTable      = t, | 
|  | 456 					ThisColumns     = key.OtherColumns, | 
|  | 457 					OtherColumns    = key.ThisColumns, | 
|  | 458 				}); | 
|  | 459 | 
|  | 460 	foreach (var t in Tables.Values) | 
|  | 461 	{ | 
|  | 462 		foreach (var key in t.ForeignKeys.Values) | 
|  | 463 		{ | 
|  | 464 			if (key.BackReference != null && key.AssociationType == AssociationType.Auto) | 
|  | 465 			{ | 
|  | 466 				if (key.ThisColumns.All(_ => _.IsPrimaryKey)) | 
|  | 467 				{ | 
|  | 468 					if (t.Columns.Values.Count(_ => _.IsPrimaryKey) == key.ThisColumns.Count) | 
|  | 469 						key.AssociationType = AssociationType.OneToOne; | 
|  | 470 					else | 
|  | 471 						key.AssociationType = AssociationType.ManyToOne; | 
|  | 472 				} | 
|  | 473 				else | 
|  | 474 					key.AssociationType = AssociationType.ManyToOne; | 
|  | 475 | 
|  | 476 				key.CanBeNull = key.ThisColumns.All(_ => _.IsNullable); | 
|  | 477 			} | 
|  | 478 		} | 
|  | 479 	} | 
|  | 480 | 
|  | 481 	foreach (var t in Tables.Values) | 
|  | 482 	{ | 
|  | 483 		foreach (var key in t.ForeignKeys.Values) | 
|  | 484 		{ | 
|  | 485 			var name = key.MemberName; | 
|  | 486 | 
|  | 487 			if (key.BackReference != null && key.ThisColumns.Count == 1 && key.ThisColumns[0].MemberName.ToLower().EndsWith("id")) | 
|  | 488 			{ | 
|  | 489 				name = key.ThisColumns[0].MemberName; | 
|  | 490 				name = name.Substring(0, name.Length - "id".Length); | 
|  | 491 | 
|  | 492 				if (!t.ForeignKeys.Values.Select(_ => _.MemberName).Concat( | 
|  | 493 					 t.Columns.    Values.Select(_ => _.MemberName)).Concat( | 
|  | 494 					 new[] { t.ClassName }).Any(_ => _ == name)) | 
|  | 495 				{ | 
|  | 496 					name = key.MemberName;; | 
|  | 497 				} | 
|  | 498 			} | 
|  | 499 | 
|  | 500 			if (name == key.MemberName) | 
|  | 501 			{ | 
|  | 502 				if (name.StartsWith("FK_")) | 
|  | 503 					name = name.Substring(3); | 
|  | 504 | 
|  | 505 				if (name.EndsWith("_BackReference")) | 
|  | 506 					name = name.Substring(0, name.Length - "_BackReference".Length); | 
|  | 507 | 
|  | 508 				name = string.Join("", name.Split('_').Where(_ => _.Length > 0 && _ != t.TableName).ToArray()); | 
|  | 509 | 
|  | 510 				if (name.Length > 0) | 
|  | 511 					name = key.AssociationType == AssociationType.OneToMany ? PluralizeAssociationName(name) : SingularizeAssociationName(name); | 
|  | 512 			} | 
|  | 513 | 
|  | 514 			if (name.Length != 0 && | 
|  | 515 				!t.ForeignKeys.Values.Select(_ => _.MemberName).Concat( | 
|  | 516 				 t.Columns.    Values.Select(_ => _.MemberName)).Concat( | 
|  | 517 				 new[] { t.ClassName }).Any(_ => _ == name)) | 
|  | 518 			{ | 
|  | 519 				key.MemberName = name; | 
|  | 520 			} | 
|  | 521 		} | 
|  | 522 	} | 
|  | 523 | 
|  | 524 	if (Tables.Values.SelectMany(_ => _.ForeignKeys.Values).Any(_ => _.AssociationType == AssociationType.OneToMany)) | 
|  | 525 		Usings.Add("System.Collections.Generic"); | 
|  | 526 | 
|  | 527 	var keyWords = new HashSet<string> | 
|  | 528 	{ | 
|  | 529 		"abstract", "as",       "base",     "bool",    "break",     "byte",     "case",       "catch",     "char",    "checked", | 
|  | 530 		"class",    "const",    "continue", "decimal", "default",   "delegate", "do",         "double",    "else",    "enum", | 
|  | 531 		"event",    "explicit", "extern",   "false",   "finally",   "fixed",    "float",      "for",       "foreach", "goto", | 
|  | 532 		"if",       "implicit", "in",       "int",     "interface", "internal", "is",         "lock",      "long",    "new", | 
|  | 533 		"null",     "object",   "operator", "out",     "override",  "params",   "private",    "protected", "public",  "readonly", | 
|  | 534 		"ref",      "return",   "sbyte",    "sealed",  "short",     "sizeof",   "stackalloc", "static",    "struct",  "switch", | 
|  | 535 		"this",     "throw",    "true",     "try",     "typeof",    "uint",     "ulong",      "unchecked", "unsafe",  "ushort", | 
|  | 536 		"using",    "virtual",  "volatile", "void",    "while" | 
|  | 537 	}; | 
|  | 538 | 
|  | 539 	foreach (var t in Tables.Values) | 
|  | 540 	{ | 
|  | 541 		if (keyWords.Contains(t.ClassName)) | 
|  | 542 			t.ClassName = "@" + t.ClassName; | 
|  | 543 | 
|  | 544 		if (keyWords.Contains(t.DataContextPropertyName)) | 
|  | 545 			t.DataContextPropertyName = "@" + t.DataContextPropertyName; | 
|  | 546 | 
|  | 547 		foreach (var col in t.Columns.Values) | 
|  | 548 			if (keyWords.Contains(col.MemberName)) | 
|  | 549 				col.MemberName = "@" + col.MemberName; | 
|  | 550 	} | 
|  | 551 | 
|  | 552 | 
|  | 553 	AfterLoadMetadata(this); | 
|  | 554 } | 
|  | 555 | 
|  | 556 Func<string,string> PluralizeAssociationName   = _ => _ + "s"; | 
|  | 557 Func<string,string> SingularizeAssociationName = _ => _; | 
|  | 558 | 
|  | 559 Action<GeneratedTextTransformation> BeforeLoadMetadata = _ => {}; | 
|  | 560 Action<GeneratedTextTransformation> AfterLoadMetadata  = _ => {}; | 
|  | 561 | 
|  | 562 Dictionary<string,Table> Tables = new Dictionary<string,Table>(); | 
|  | 563 | 
|  | 564 public partial class Table | 
|  | 565 { | 
|  | 566 	public string       Owner; | 
|  | 567 	public string       TableName; | 
|  | 568 	public string       ClassName; | 
|  | 569 	public string       DataContextPropertyName; | 
|  | 570 	public string       BaseClassName; | 
|  | 571 	public bool         IsView; | 
|  | 572 	public string		Description; | 
|  | 573 	public List<string> Attributes = new List<string>(); | 
|  | 574 | 
|  | 575 	public Dictionary<string,Column>     Columns     = new Dictionary<string,Column>(); | 
|  | 576 	public Dictionary<string,ForeignKey> ForeignKeys = new Dictionary<string,ForeignKey>(); | 
|  | 577 } | 
|  | 578 | 
|  | 579 public partial class Column | 
|  | 580 { | 
|  | 581 	public int          ID; | 
|  | 582 	public string       ColumnName; // Column name in database | 
|  | 583 	public string       MemberName; // Member name of the generated class | 
|  | 584 	public bool         IsNullable; | 
|  | 585 	public bool         IsIdentity; | 
|  | 586 	public string       Type;       // Type of the generated member | 
|  | 587 	public string       ColumnType; // Type of the column in database | 
|  | 588 	public bool         IsClass; | 
|  | 589 	public DbType       DbType; | 
|  | 590 	public SqlDbType    SqlDbType; | 
|  | 591 	public long         Length; | 
|  | 592 	public int          Precision; | 
|  | 593 	public int          Scale; | 
|  | 594 	public string		Description; | 
|  | 595 | 
|  | 596 	public int          PKIndex = -1; | 
|  | 597 	public List<string> Attributes = new List<string>(); | 
|  | 598 | 
|  | 599 	public bool IsPrimaryKey { get { return PKIndex >= 0; } } | 
|  | 600 } | 
|  | 601 | 
|  | 602 public enum AssociationType | 
|  | 603 { | 
|  | 604 	Auto, | 
|  | 605 	OneToOne, | 
|  | 606 	OneToMany, | 
|  | 607 	ManyToOne, | 
|  | 608 } | 
|  | 609 | 
|  | 610 public partial class ForeignKey | 
|  | 611 { | 
|  | 612 	public string       KeyName; | 
|  | 613 	public string       MemberName; | 
|  | 614 	public Table        OtherTable; | 
|  | 615 	public List<Column> ThisColumns  = new List<Column>(); | 
|  | 616 	public List<Column> OtherColumns = new List<Column>(); | 
|  | 617 	public List<string> Attributes   = new List<string>(); | 
|  | 618 	public bool         CanBeNull    = true; | 
|  | 619 	public ForeignKey   BackReference; | 
|  | 620 | 
|  | 621 	private AssociationType _associationType = AssociationType.Auto; | 
|  | 622 	public  AssociationType  AssociationType | 
|  | 623 	{ | 
|  | 624 		get { return _associationType; } | 
|  | 625 		set | 
|  | 626 		{ | 
|  | 627 			_associationType = value; | 
|  | 628 | 
|  | 629 			if (BackReference != null) | 
|  | 630 			{ | 
|  | 631 				switch (value) | 
|  | 632 				{ | 
|  | 633 					case AssociationType.Auto      : BackReference.AssociationType = AssociationType.Auto;      break; | 
|  | 634 					case AssociationType.OneToOne  : BackReference.AssociationType = AssociationType.OneToOne;  break; | 
|  | 635 					case AssociationType.OneToMany : BackReference.AssociationType = AssociationType.ManyToOne; break; | 
|  | 636 					case AssociationType.ManyToOne : BackReference.AssociationType = AssociationType.OneToMany; break; | 
|  | 637 				} | 
|  | 638 			} | 
|  | 639 		} | 
|  | 640 	} | 
|  | 641 } | 
|  | 642 | 
|  | 643 #> |