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

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
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 #>