/PetaPoco/Models/Generated/PetaPoco.Core.ttinclude
Unknown | 1617 lines | 1358 code | 259 blank | 0 comment | 0 complexity | 43706cc72b9bc0433726acc572c81d91 MD5 | raw file
1<#@ template language="C#v3.5" hostspecific="True" #> 2<#@ assembly name="EnvDTE" #> 3<#@ assembly name="System.Core.dll" #> 4<#@ assembly name="System.Data" #> 5<#@ assembly name="System.Xml" #> 6<#@ assembly name="System.Configuration" #> 7<#@ assembly name="System.Windows.Forms" #> 8<#@ import namespace="System.Collections.Generic" #> 9<#@ import namespace="System.Data" #> 10<#@ import namespace="System.Data.SqlClient" #> 11<#@ import namespace="System.Data.Common" #> 12<#@ import namespace="System.Diagnostics" #> 13<#@ import namespace="System.Globalization" #> 14<#@ import namespace="System.IO" #> 15<#@ import namespace="System.Linq" #> 16<#@ import namespace="System.Text" #> 17<#@ import namespace="System.Text.RegularExpressions" #> 18<#@ import namespace="System.Configuration" #> 19<#@ import namespace="System.Windows.Forms" #> 20<#+ 21 22/* 23 This code is part of the PetaPoco project (http://www.toptensoftware.com/petapoco). 24 It is based on the SubSonic T4 templates but has been considerably re-organized and reduced 25 26 ----------------------------------------------------------------------------------------- 27 28 This template can read minimal schema information from the following databases: 29 30 * SQL Server 31 * SQL Server CE 32 * MySQL 33 * PostGreSQL 34 * Oracle 35 36 For connection and provider settings the template will look for the web.config or app.config file of the 37 containing Visual Studio project. It will not however read DbProvider settings from this file. 38 39 In order to work, the appropriate driver must be registered in the system machine.config file. If you're 40 using Visual Studio 2010 the file you want is here: 41 42 C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config 43 44 After making changes to machine.config you will also need to restart Visual Studio. 45 46 Here's a typical set of entries that might help if you're stuck: 47 48 <system.data> 49 <DbProviderFactories> 50 <add name="Odbc Data Provider" invariant="System.Data.Odbc" description=".Net Framework Data Provider for Odbc" type="System.Data.Odbc.OdbcFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> 51 <add name="OleDb Data Provider" invariant="System.Data.OleDb" description=".Net Framework Data Provider for OleDb" type="System.Data.OleDb.OleDbFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> 52 <add name="OracleClient Data Provider" invariant="System.Data.OracleClient" description=".Net Framework Data Provider for Oracle" type="System.Data.OracleClient.OracleClientFactory, System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> 53 <add name="SqlClient Data Provider" invariant="System.Data.SqlClient" description=".Net Framework Data Provider for SqlServer" type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> 54 <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.3.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"/> 55 <add name="Microsoft SQL Server Compact Data Provider" invariant="System.Data.SqlServerCe.3.5" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=3.5.1.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"/><add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"/> 56 <add name="Npgsql Data Provider" invariant="Npgsql" support="FF" description=".Net Framework Data Provider for Postgresql Server" type="Npgsql.NpgsqlFactory, Npgsql, Version=2.0.11.91, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7" /> 57 </DbProviderFactories> 58 </system.data> 59 60 Also, the providers and their dependencies need to be installed to GAC. 61 62 Eg; this is how I installed the drivers for PostgreSQL 63 64 gacutil /i Npgsql.dll 65 gacutil /i Mono.Security.dll 66 67 ----------------------------------------------------------------------------------------- 68 69 SubSonic - http://subsonicproject.com 70 71 The contents of this file are subject to the New BSD 72 License (the "License"); you may not use this file 73 except in compliance with the License. You may obtain a copy of 74 the License at http://www.opensource.org/licenses/bsd-license.php 75 76 Software distributed under the License is distributed on an 77 "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 78 implied. See the License for the specific language governing 79 rights and limitations under the License. 80*/ 81 82string ConnectionStringName = ""; 83string Namespace = ""; 84string RepoName = ""; 85string ClassPrefix = ""; 86string ClassSuffix = ""; 87string SchemaName = null; 88bool IncludeViews = false; 89bool GenerateOperations = false; 90bool GenerateCommon = true; 91bool GeneratePocos = true; 92bool TrackModifiedColumns = false; 93 94 95public class Table 96{ 97 public List<Column> Columns; 98 public string Name; 99 public string Schema; 100 public bool IsView; 101 public string CleanName; 102 public string ClassName; 103 public string SequenceName; 104 public bool Ignore; 105 106 public Column PK 107 { 108 get 109 { 110 return this.Columns.SingleOrDefault(x=>x.IsPK); 111 } 112 } 113 114 public Column GetColumn(string columnName) 115 { 116 return Columns.Single(x=>string.Compare(x.Name, columnName, true)==0); 117 } 118 119 public Column this[string columnName] 120 { 121 get 122 { 123 return GetColumn(columnName); 124 } 125 } 126 127} 128 129public class Column 130{ 131 public string Name; 132 public string PropertyName; 133 public string PropertyType; 134 public bool IsPK; 135 public bool IsNullable; 136 public bool IsAutoIncrement; 137 public bool Ignore; 138} 139 140public class Tables : List<Table> 141{ 142 public Tables() 143 { 144 } 145 146 public Table GetTable(string tableName) 147 { 148 return this.Single(x=>string.Compare(x.Name, tableName, true)==0); 149 } 150 151 public Table this[string tableName] 152 { 153 get 154 { 155 return GetTable(tableName); 156 } 157 } 158 159} 160 161 162static Regex rxCleanUp = new Regex(@"[^\w\d_]", RegexOptions.Compiled); 163 164static Func<string, string> CleanUp = (str) => 165{ 166 str = rxCleanUp.Replace(str, "_"); 167 if (char.IsDigit(str[0])) str = "_" + str; 168 169 return str; 170}; 171 172string CheckNullable(Column col) 173{ 174 string result=""; 175 if(col.IsNullable && 176 col.PropertyType !="byte[]" && 177 col.PropertyType !="string" && 178 col.PropertyType !="Microsoft.SqlServer.Types.SqlGeography" && 179 col.PropertyType !="Microsoft.SqlServer.Types.SqlGeometry" 180 ) 181 result="?"; 182 return result; 183} 184 185string GetConnectionString(ref string connectionStringName, out string providerName) 186{ 187 var _CurrentProject = GetCurrentProject(); 188 189 providerName=null; 190 191 string result=""; 192 ExeConfigurationFileMap configFile = new ExeConfigurationFileMap(); 193 configFile.ExeConfigFilename = GetConfigPath(); 194 195 if (string.IsNullOrEmpty(configFile.ExeConfigFilename)) 196 throw new ArgumentNullException("The project does not contain App.config or Web.config file."); 197 198 199 var config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None); 200 var connSection=config.ConnectionStrings; 201 202 //if the connectionString is empty - which is the defauls 203 //look for count-1 - this is the last connection string 204 //and takes into account AppServices and LocalSqlServer 205 if(string.IsNullOrEmpty(connectionStringName)) 206 { 207 if(connSection.ConnectionStrings.Count>1) 208 { 209 connectionStringName = connSection.ConnectionStrings[connSection.ConnectionStrings.Count-1].Name; 210 result=connSection.ConnectionStrings[connSection.ConnectionStrings.Count-1].ConnectionString; 211 providerName=connSection.ConnectionStrings[connSection.ConnectionStrings.Count-1].ProviderName; 212 } 213 } 214 else 215 { 216 try 217 { 218 result=connSection.ConnectionStrings[connectionStringName].ConnectionString; 219 providerName=connSection.ConnectionStrings[connectionStringName].ProviderName; 220 } 221 catch 222 { 223 result="There is no connection string name called '"+connectionStringName+"'"; 224 } 225 } 226 227// if (String.IsNullOrEmpty(providerName)) 228// providerName="System.Data.SqlClient"; 229 230 return result; 231} 232 233string _connectionString=""; 234string _providerName=""; 235 236void InitConnectionString() 237{ 238 if(String.IsNullOrEmpty(_connectionString)) 239 { 240 _connectionString=GetConnectionString(ref ConnectionStringName, out _providerName); 241 242 if(_connectionString.Contains("|DataDirectory|")) 243 { 244 //have to replace it 245 string dataFilePath=GetDataDirectory(); 246 _connectionString=_connectionString.Replace("|DataDirectory|",dataFilePath); 247 } 248 } 249} 250 251public string ConnectionString 252{ 253 get 254 { 255 InitConnectionString(); 256 return _connectionString; 257 } 258} 259 260public string ProviderName 261{ 262 get 263 { 264 InitConnectionString(); 265 return _providerName; 266 } 267} 268 269public EnvDTE.Project GetCurrentProject() { 270 271 IServiceProvider _ServiceProvider = (IServiceProvider)Host; 272 if (_ServiceProvider == null) 273 throw new Exception("Host property returned unexpected value (null)"); 274 275 EnvDTE.DTE dte = (EnvDTE.DTE)_ServiceProvider.GetService(typeof(EnvDTE.DTE)); 276 if (dte == null) 277 throw new Exception("Unable to retrieve EnvDTE.DTE"); 278 279 Array activeSolutionProjects = (Array)dte.ActiveSolutionProjects; 280 if (activeSolutionProjects == null) 281 throw new Exception("DTE.ActiveSolutionProjects returned null"); 282 283 EnvDTE.Project dteProject = (EnvDTE.Project)activeSolutionProjects.GetValue(0); 284 if (dteProject == null) 285 throw new Exception("DTE.ActiveSolutionProjects[0] returned null"); 286 287 return dteProject; 288 289} 290 291private string GetProjectPath() 292{ 293 EnvDTE.Project project = GetCurrentProject(); 294 System.IO.FileInfo info = new System.IO.FileInfo(project.FullName); 295 return info.Directory.FullName; 296} 297 298private string GetConfigPath() 299{ 300 EnvDTE.Project project = GetCurrentProject(); 301 foreach (EnvDTE.ProjectItem item in project.ProjectItems) 302 { 303 // if it is the app.config file, then open it up 304 if (item.Name.Equals("App.config",StringComparison.InvariantCultureIgnoreCase) || item.Name.Equals("Web.config",StringComparison.InvariantCultureIgnoreCase)) 305 return GetProjectPath() + "\\" + item.Name; 306 } 307 return String.Empty; 308} 309 310public string GetDataDirectory() 311{ 312 EnvDTE.Project project=GetCurrentProject(); 313 return System.IO.Path.GetDirectoryName(project.FileName)+"\\App_Data\\"; 314} 315 316static string zap_password(string connectionString) 317{ 318 var rx = new Regex("password=.*;", RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.IgnoreCase); 319 return rx.Replace(connectionString, "password=**zapped**;"); 320} 321 322 323 324Tables LoadTables() 325{ 326 InitConnectionString(); 327 328 WriteLine("// This file was automatically generated by the PetaPoco T4 Template"); 329 WriteLine("// Do not make changes directly to this file - edit the template instead"); 330 WriteLine("// "); 331 WriteLine("// The following connection settings were used to generate this file"); 332 WriteLine("// "); 333 WriteLine("// Connection String Name: `{0}`", ConnectionStringName); 334 WriteLine("// Provider: `{0}`", ProviderName); 335 WriteLine("// Connection String: `{0}`", zap_password(ConnectionString)); 336 WriteLine("// Schema: `{0}`", SchemaName); 337 WriteLine("// Include Views: `{0}`", IncludeViews); 338 WriteLine(""); 339 340 DbProviderFactory _factory; 341 try 342 { 343 _factory = DbProviderFactories.GetFactory(ProviderName); 344 } 345 catch (Exception x) 346 { 347 var error=x.Message.Replace("\r\n", "\n").Replace("\n", " "); 348 Warning(string.Format("Failed to load provider `{0}` - {1}", ProviderName, error)); 349 WriteLine(""); 350 WriteLine("// -----------------------------------------------------------------------------------------"); 351 WriteLine("// Failed to load provider `{0}` - {1}", ProviderName, error); 352 WriteLine("// -----------------------------------------------------------------------------------------"); 353 WriteLine(""); 354 return new Tables(); 355 } 356 357 try 358 { 359 Tables result; 360 using(var conn=_factory.CreateConnection()) 361 { 362 conn.ConnectionString=ConnectionString; 363 conn.Open(); 364 365 SchemaReader reader=null; 366 367 if (_factory.GetType().Name == "MySqlClientFactory") 368 { 369 // MySql 370 reader=new MySqlSchemaReader(); 371 } 372 else if (_factory.GetType().Name == "SqlCeProviderFactory") 373 { 374 // SQL CE 375 reader=new SqlServerCeSchemaReader(); 376 } 377 else if (_factory.GetType().Name == "NpgsqlFactory") 378 { 379 // PostgreSQL 380 reader=new PostGreSqlSchemaReader(); 381 } 382 else if (_factory.GetType().Name == "OracleClientFactory") 383 { 384 // Oracle 385 reader=new OracleSchemaReader(); 386 } 387 else 388 { 389 // Assume SQL Server 390 reader=new SqlServerSchemaReader(); 391 } 392 393 reader.outer=this; 394 result=reader.ReadSchema(conn, _factory); 395 396 // Remove unrequired tables/views 397 for (int i=result.Count-1; i>=0; i--) 398 { 399 if (SchemaName!=null && string.Compare(result[i].Schema, SchemaName, true)!=0) 400 { 401 result.RemoveAt(i); 402 continue; 403 } 404 if (!IncludeViews && result[i].IsView) 405 { 406 result.RemoveAt(i); 407 continue; 408 } 409 } 410 411 conn.Close(); 412 413 414 var rxClean = new Regex("^(Equals|GetHashCode|GetType|ToString|repo|Save|IsNew|Insert|Update|Delete|Exists|SingleOrDefault|Single|First|FirstOrDefault|Fetch|Page|Query)$"); 415 foreach (var t in result) 416 { 417 t.ClassName = ClassPrefix + t.ClassName + ClassSuffix; 418 foreach (var c in t.Columns) 419 { 420 c.PropertyName = rxClean.Replace(c.PropertyName, "_$1"); 421 422 // Make sure property name doesn't clash with class name 423 if (c.PropertyName == t.ClassName) 424 c.PropertyName = "_" + c.PropertyName; 425 } 426 } 427 428 return result; 429 } 430 } 431 catch (Exception x) 432 { 433 var error=x.Message.Replace("\r\n", "\n").Replace("\n", " "); 434 Warning(string.Format("Failed to read database schema - {0}", error)); 435 WriteLine(""); 436 WriteLine("// -----------------------------------------------------------------------------------------"); 437 WriteLine("// Failed to read database schema - {0}", error); 438 WriteLine("// -----------------------------------------------------------------------------------------"); 439 WriteLine(""); 440 return new Tables(); 441 } 442 443 444} 445 446abstract class SchemaReader 447{ 448 public abstract Tables ReadSchema(DbConnection connection, DbProviderFactory factory); 449 public GeneratedTextTransformation outer; 450 public void WriteLine(string o) 451 { 452 outer.WriteLine(o); 453 } 454 455} 456 457class SqlServerSchemaReader : SchemaReader 458{ 459 // SchemaReader.ReadSchema 460 public override Tables ReadSchema(DbConnection connection, DbProviderFactory factory) 461 { 462 var result=new Tables(); 463 464 _connection=connection; 465 _factory=factory; 466 467 var cmd=_factory.CreateCommand(); 468 cmd.Connection=connection; 469 cmd.CommandText=TABLE_SQL; 470 471 //pull the tables in a reader 472 using(cmd) 473 { 474 475 using (var rdr=cmd.ExecuteReader()) 476 { 477 while(rdr.Read()) 478 { 479 Table tbl=new Table(); 480 tbl.Name=rdr["TABLE_NAME"].ToString(); 481 tbl.Schema=rdr["TABLE_SCHEMA"].ToString(); 482 tbl.IsView=string.Compare(rdr["TABLE_TYPE"].ToString(), "View", true)==0; 483 tbl.CleanName=CleanUp(tbl.Name); 484 tbl.ClassName=Inflector.MakeSingular(tbl.CleanName); 485 486 result.Add(tbl); 487 } 488 } 489 } 490 491 foreach (var tbl in result) 492 { 493 tbl.Columns=LoadColumns(tbl); 494 495 // Mark the primary key 496 string PrimaryKey=GetPK(tbl.Name); 497 var pkColumn=tbl.Columns.SingleOrDefault(x=>x.Name.ToLower().Trim()==PrimaryKey.ToLower().Trim()); 498 if(pkColumn!=null) 499 { 500 pkColumn.IsPK=true; 501 } 502 } 503 504 505 return result; 506 } 507 508 DbConnection _connection; 509 DbProviderFactory _factory; 510 511 512 List<Column> LoadColumns(Table tbl) 513 { 514 515 using (var cmd=_factory.CreateCommand()) 516 { 517 cmd.Connection=_connection; 518 cmd.CommandText=COLUMN_SQL; 519 520 var p = cmd.CreateParameter(); 521 p.ParameterName = "@tableName"; 522 p.Value=tbl.Name; 523 cmd.Parameters.Add(p); 524 525 p = cmd.CreateParameter(); 526 p.ParameterName = "@schemaName"; 527 p.Value=tbl.Schema; 528 cmd.Parameters.Add(p); 529 530 var result=new List<Column>(); 531 using (IDataReader rdr=cmd.ExecuteReader()) 532 { 533 while(rdr.Read()) 534 { 535 Column col=new Column(); 536 col.Name=rdr["ColumnName"].ToString(); 537 col.PropertyName=CleanUp(col.Name); 538 col.PropertyType=GetPropertyType(rdr["DataType"].ToString()); 539 col.IsNullable=rdr["IsNullable"].ToString()=="YES"; 540 col.IsAutoIncrement=((int)rdr["IsIdentity"])==1; 541 result.Add(col); 542 } 543 } 544 545 return result; 546 } 547 } 548 549 string GetPK(string table){ 550 551 string sql=@"SELECT c.name AS ColumnName 552 FROM sys.indexes AS i 553 INNER JOIN sys.index_columns AS ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id 554 INNER JOIN sys.objects AS o ON i.object_id = o.object_id 555 LEFT OUTER JOIN sys.columns AS c ON ic.object_id = c.object_id AND c.column_id = ic.column_id 556 WHERE (i.type = 1) AND (o.name = @tableName)"; 557 558 using (var cmd=_factory.CreateCommand()) 559 { 560 cmd.Connection=_connection; 561 cmd.CommandText=sql; 562 563 var p = cmd.CreateParameter(); 564 p.ParameterName = "@tableName"; 565 p.Value=table; 566 cmd.Parameters.Add(p); 567 568 var result=cmd.ExecuteScalar(); 569 570 if(result!=null) 571 return result.ToString(); 572 } 573 574 return ""; 575 } 576 577 string GetPropertyType(string sqlType) 578 { 579 string sysType="string"; 580 switch (sqlType) 581 { 582 case "bigint": 583 sysType = "long"; 584 break; 585 case "smallint": 586 sysType= "short"; 587 break; 588 case "int": 589 sysType= "int"; 590 break; 591 case "uniqueidentifier": 592 sysType= "Guid"; 593 break; 594 case "smalldatetime": 595 case "datetime": 596 case "date": 597 case "time": 598 sysType= "DateTime"; 599 break; 600 case "float": 601 sysType="double"; 602 break; 603 case "real": 604 sysType="float"; 605 break; 606 case "numeric": 607 case "smallmoney": 608 case "decimal": 609 case "money": 610 sysType= "decimal"; 611 break; 612 case "tinyint": 613 sysType = "byte"; 614 break; 615 case "bit": 616 sysType= "bool"; 617 break; 618 case "image": 619 case "binary": 620 case "varbinary": 621 case "timestamp": 622 sysType= "byte[]"; 623 break; 624 case "geography": 625 sysType = "Microsoft.SqlServer.Types.SqlGeography"; 626 break; 627 case "geometry": 628 sysType = "Microsoft.SqlServer.Types.SqlGeometry"; 629 break; 630 } 631 return sysType; 632 } 633 634 635 636 const string TABLE_SQL=@"SELECT * 637 FROM INFORMATION_SCHEMA.TABLES 638 WHERE TABLE_TYPE='BASE TABLE' OR TABLE_TYPE='VIEW'"; 639 640 const string COLUMN_SQL=@"SELECT 641 TABLE_CATALOG AS [Database], 642 TABLE_SCHEMA AS Owner, 643 TABLE_NAME AS TableName, 644 COLUMN_NAME AS ColumnName, 645 ORDINAL_POSITION AS OrdinalPosition, 646 COLUMN_DEFAULT AS DefaultSetting, 647 IS_NULLABLE AS IsNullable, DATA_TYPE AS DataType, 648 CHARACTER_MAXIMUM_LENGTH AS MaxLength, 649 DATETIME_PRECISION AS DatePrecision, 650 COLUMNPROPERTY(object_id('[' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']'), COLUMN_NAME, 'IsIdentity') AS IsIdentity, 651 COLUMNPROPERTY(object_id('[' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']'), COLUMN_NAME, 'IsComputed') as IsComputed 652 FROM INFORMATION_SCHEMA.COLUMNS 653 WHERE TABLE_NAME=@tableName AND TABLE_SCHEMA=@schemaName 654 ORDER BY OrdinalPosition ASC"; 655 656} 657 658class SqlServerCeSchemaReader : SchemaReader 659{ 660 // SchemaReader.ReadSchema 661 public override Tables ReadSchema(DbConnection connection, DbProviderFactory factory) 662 { 663 var result=new Tables(); 664 665 _connection=connection; 666 _factory=factory; 667 668 var cmd=_factory.CreateCommand(); 669 cmd.Connection=connection; 670 cmd.CommandText=TABLE_SQL; 671 672 //pull the tables in a reader 673 using(cmd) 674 { 675 using (var rdr=cmd.ExecuteReader()) 676 { 677 while(rdr.Read()) 678 { 679 Table tbl=new Table(); 680 tbl.Name=rdr["TABLE_NAME"].ToString(); 681 tbl.CleanName=CleanUp(tbl.Name); 682 tbl.ClassName=Inflector.MakeSingular(tbl.CleanName); 683 tbl.Schema=null; 684 tbl.IsView=false; 685 result.Add(tbl); 686 } 687 } 688 } 689 690 foreach (var tbl in result) 691 { 692 tbl.Columns=LoadColumns(tbl); 693 694 // Mark the primary key 695 string PrimaryKey=GetPK(tbl.Name); 696 var pkColumn=tbl.Columns.SingleOrDefault(x=>x.Name.ToLower().Trim()==PrimaryKey.ToLower().Trim()); 697 if(pkColumn!=null) 698 pkColumn.IsPK=true; 699 } 700 701 702 return result; 703 } 704 705 DbConnection _connection; 706 DbProviderFactory _factory; 707 708 709 List<Column> LoadColumns(Table tbl) 710 { 711 712 using (var cmd=_factory.CreateCommand()) 713 { 714 cmd.Connection=_connection; 715 cmd.CommandText=COLUMN_SQL; 716 717 var p = cmd.CreateParameter(); 718 p.ParameterName = "@tableName"; 719 p.Value=tbl.Name; 720 cmd.Parameters.Add(p); 721 722 var result=new List<Column>(); 723 using (IDataReader rdr=cmd.ExecuteReader()) 724 { 725 while(rdr.Read()) 726 { 727 Column col=new Column(); 728 col.Name=rdr["ColumnName"].ToString(); 729 col.PropertyName=CleanUp(col.Name); 730 col.PropertyType=GetPropertyType(rdr["DataType"].ToString()); 731 col.IsNullable=rdr["IsNullable"].ToString()=="YES"; 732 col.IsAutoIncrement=rdr["AUTOINC_INCREMENT"]!=DBNull.Value; 733 result.Add(col); 734 } 735 } 736 737 return result; 738 } 739 } 740 741 string GetPK(string table){ 742 743 string sql=@"SELECT KCU.COLUMN_NAME 744 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU 745 JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC 746 ON KCU.CONSTRAINT_NAME=TC.CONSTRAINT_NAME 747 WHERE TC.CONSTRAINT_TYPE='PRIMARY KEY' 748 AND KCU.TABLE_NAME=@tableName"; 749 750 using (var cmd=_factory.CreateCommand()) 751 { 752 cmd.Connection=_connection; 753 cmd.CommandText=sql; 754 755 var p = cmd.CreateParameter(); 756 p.ParameterName = "@tableName"; 757 p.Value=table; 758 cmd.Parameters.Add(p); 759 760 var result=cmd.ExecuteScalar(); 761 762 if(result!=null) 763 return result.ToString(); 764 } 765 766 return ""; 767 } 768 769 string GetPropertyType(string sqlType) 770 { 771 string sysType="string"; 772 switch (sqlType) 773 { 774 case "bigint": 775 sysType = "long"; 776 break; 777 case "smallint": 778 sysType= "short"; 779 break; 780 case "int": 781 sysType= "int"; 782 break; 783 case "uniqueidentifier": 784 sysType= "Guid"; 785 break; 786 case "smalldatetime": 787 case "datetime": 788 case "date": 789 case "time": 790 sysType= "DateTime"; 791 break; 792 case "float": 793 sysType="double"; 794 break; 795 case "real": 796 sysType="float"; 797 break; 798 case "numeric": 799 case "smallmoney": 800 case "decimal": 801 case "money": 802 sysType= "decimal"; 803 break; 804 case "tinyint": 805 sysType = "byte"; 806 break; 807 case "bit": 808 sysType= "bool"; 809 break; 810 case "image": 811 case "binary": 812 case "varbinary": 813 case "timestamp": 814 sysType= "byte[]"; 815 break; 816 } 817 return sysType; 818 } 819 820 821 822 const string TABLE_SQL=@"SELECT * 823 FROM INFORMATION_SCHEMA.TABLES 824 WHERE TABLE_TYPE='TABLE'"; 825 826 const string COLUMN_SQL=@"SELECT 827 TABLE_CATALOG AS [Database], 828 TABLE_SCHEMA AS Owner, 829 TABLE_NAME AS TableName, 830 COLUMN_NAME AS ColumnName, 831 ORDINAL_POSITION AS OrdinalPosition, 832 COLUMN_DEFAULT AS DefaultSetting, 833 IS_NULLABLE AS IsNullable, DATA_TYPE AS DataType, 834 AUTOINC_INCREMENT, 835 CHARACTER_MAXIMUM_LENGTH AS MaxLength, 836 DATETIME_PRECISION AS DatePrecision 837 FROM INFORMATION_SCHEMA.COLUMNS 838 WHERE TABLE_NAME=@tableName 839 ORDER BY OrdinalPosition ASC"; 840 841} 842 843 844class PostGreSqlSchemaReader : SchemaReader 845{ 846 // SchemaReader.ReadSchema 847 public override Tables ReadSchema(DbConnection connection, DbProviderFactory factory) 848 { 849 var result=new Tables(); 850 851 _connection=connection; 852 _factory=factory; 853 854 var cmd=_factory.CreateCommand(); 855 cmd.Connection=connection; 856 cmd.CommandText=TABLE_SQL; 857 858 //pull the tables in a reader 859 using(cmd) 860 { 861 using (var rdr=cmd.ExecuteReader()) 862 { 863 while(rdr.Read()) 864 { 865 Table tbl=new Table(); 866 tbl.Name=rdr["table_name"].ToString(); 867 tbl.Schema=rdr["table_schema"].ToString(); 868 tbl.IsView=string.Compare(rdr["table_type"].ToString(), "View", true)==0; 869 tbl.CleanName=CleanUp(tbl.Name); 870 tbl.ClassName=Inflector.MakeSingular(tbl.CleanName); 871 result.Add(tbl); 872 } 873 } 874 } 875 876 foreach (var tbl in result) 877 { 878 tbl.Columns=LoadColumns(tbl); 879 880 // Mark the primary key 881 string PrimaryKey=GetPK(tbl.Name); 882 var pkColumn=tbl.Columns.SingleOrDefault(x=>x.Name.ToLower().Trim()==PrimaryKey.ToLower().Trim()); 883 if(pkColumn!=null) 884 pkColumn.IsPK=true; 885 } 886 887 888 return result; 889 } 890 891 DbConnection _connection; 892 DbProviderFactory _factory; 893 894 895 List<Column> LoadColumns(Table tbl) 896 { 897 898 using (var cmd=_factory.CreateCommand()) 899 { 900 cmd.Connection=_connection; 901 cmd.CommandText=COLUMN_SQL; 902 903 var p = cmd.CreateParameter(); 904 p.ParameterName = "@tableName"; 905 p.Value=tbl.Name; 906 cmd.Parameters.Add(p); 907 908 var result=new List<Column>(); 909 using (IDataReader rdr=cmd.ExecuteReader()) 910 { 911 while(rdr.Read()) 912 { 913 Column col=new Column(); 914 col.Name=rdr["column_name"].ToString(); 915 col.PropertyName=CleanUp(col.Name); 916 col.PropertyType=GetPropertyType(rdr["udt_name"].ToString()); 917 col.IsNullable=rdr["is_nullable"].ToString()=="YES"; 918 col.IsAutoIncrement = rdr["column_default"].ToString().StartsWith("nextval("); 919 result.Add(col); 920 } 921 } 922 923 return result; 924 } 925 } 926 927 string GetPK(string table){ 928 929 string sql=@"SELECT kcu.column_name 930 FROM information_schema.key_column_usage kcu 931 JOIN information_schema.table_constraints tc 932 ON kcu.constraint_name=tc.constraint_name 933 WHERE lower(tc.constraint_type)='primary key' 934 AND kcu.table_name=@tablename"; 935 936 using (var cmd=_factory.CreateCommand()) 937 { 938 cmd.Connection=_connection; 939 cmd.CommandText=sql; 940 941 var p = cmd.CreateParameter(); 942 p.ParameterName = "@tableName"; 943 p.Value=table; 944 cmd.Parameters.Add(p); 945 946 var result=cmd.ExecuteScalar(); 947 948 if(result!=null) 949 return result.ToString(); 950 } 951 952 return ""; 953 } 954 955 string GetPropertyType(string sqlType) 956 { 957 switch (sqlType) 958 { 959 case "int8": 960 case "serial8": 961 return "long"; 962 963 case "bool": 964 return "bool"; 965 966 case "bytea ": 967 return "byte[]"; 968 969 case "float8": 970 return "double"; 971 972 case "int4": 973 case "serial4": 974 return "int"; 975 976 case "money ": 977 return "decimal"; 978 979 case "numeric": 980 return "decimal"; 981 982 case "float4": 983 return "float"; 984 985 case "int2": 986 return "short"; 987 988 case "time": 989 case "timetz": 990 case "timestamp": 991 case "timestamptz": 992 case "date": 993 return "DateTime"; 994 995 default: 996 return "string"; 997 } 998 } 999 1000 1001 1002 const string TABLE_SQL=@" 1003 SELECT table_name, table_schema, table_type 1004 FROM information_schema.tables 1005 WHERE (table_type='BASE TABLE' OR table_type='VIEW') 1006 AND table_schema NOT IN ('pg_catalog', 'information_schema'); 1007 "; 1008 1009 const string COLUMN_SQL=@" 1010 SELECT column_name, is_nullable, udt_name, column_default 1011 FROM information_schema.columns 1012 WHERE table_name=@tableName; 1013 "; 1014 1015} 1016 1017class MySqlSchemaReader : SchemaReader 1018{ 1019 // SchemaReader.ReadSchema 1020 public override Tables ReadSchema(DbConnection connection, DbProviderFactory factory) 1021 { 1022 var result=new Tables(); 1023 1024 1025 var cmd=factory.CreateCommand(); 1026 cmd.Connection=connection; 1027 cmd.CommandText=TABLE_SQL; 1028 1029 //pull the tables in a reader 1030 using(cmd) 1031 { 1032 using (var rdr=cmd.ExecuteReader()) 1033 { 1034 while(rdr.Read()) 1035 { 1036 Table tbl=new Table(); 1037 tbl.Name=rdr["TABLE_NAME"].ToString(); 1038 tbl.Schema=rdr["TABLE_SCHEMA"].ToString(); 1039 tbl.IsView=string.Compare(rdr["TABLE_TYPE"].ToString(), "View", true)==0; 1040 tbl.CleanName=CleanUp(tbl.Name); 1041 tbl.ClassName=Inflector.MakeSingular(tbl.CleanName); 1042 result.Add(tbl); 1043 } 1044 } 1045 } 1046 1047 1048 //this will return everything for the DB 1049 var schema = connection.GetSchema("COLUMNS"); 1050 1051 //loop again - but this time pull by table name 1052 foreach (var item in result) 1053 { 1054 item.Columns=new List<Column>(); 1055 1056 //pull the columns from the schema 1057 var columns = schema.Select("TABLE_NAME='" + item.Name + "'"); 1058 foreach (var row in columns) 1059 { 1060 Column col=new Column(); 1061 col.Name=row["COLUMN_NAME"].ToString(); 1062 col.PropertyName=CleanUp(col.Name); 1063 col.PropertyType=GetPropertyType(row); 1064 col.IsNullable=row["IS_NULLABLE"].ToString()=="YES"; 1065 col.IsPK=row["COLUMN_KEY"].ToString()=="PRI"; 1066 col.IsAutoIncrement=row["extra"].ToString().ToLower().IndexOf("auto_increment")>=0; 1067 1068 item.Columns.Add(col); 1069 } 1070 } 1071 1072 return result; 1073 1074 } 1075 1076 static string GetPropertyType(DataRow row) 1077 { 1078 bool bUnsigned = row["COLUMN_TYPE"].ToString().IndexOf("unsigned")>=0; 1079 string propType="string"; 1080 switch (row["DATA_TYPE"].ToString()) 1081 { 1082 case "bigint": 1083 propType= bUnsigned ? "ulong" : "long"; 1084 break; 1085 case "int": 1086 propType= bUnsigned ? "uint" : "int"; 1087 break; 1088 case "smallint": 1089 propType= bUnsigned ? "ushort" : "short"; 1090 break; 1091 case "guid": 1092 propType= "Guid"; 1093 break; 1094 case "smalldatetime": 1095 case "date": 1096 case "datetime": 1097 case "timestamp": 1098 propType= "DateTime"; 1099 break; 1100 case "float": 1101 propType="float"; 1102 break; 1103 case "double": 1104 propType="double"; 1105 break; 1106 case "numeric": 1107 case "smallmoney": 1108 case "decimal": 1109 case "money": 1110 propType= "decimal"; 1111 break; 1112 case "bit": 1113 case "bool": 1114 case "boolean": 1115 propType= "bool"; 1116 break; 1117 case "tinyint": 1118 propType = bUnsigned ? "byte" : "sbyte"; 1119 break; 1120 case "image": 1121 case "binary": 1122 case "blob": 1123 case "mediumblob": 1124 case "longblob": 1125 case "varbinary": 1126 propType= "byte[]"; 1127 break; 1128 1129 } 1130 return propType; 1131 } 1132 1133 const string TABLE_SQL=@" 1134 SELECT * 1135 FROM information_schema.tables 1136 WHERE (table_type='BASE TABLE' OR table_type='VIEW') 1137 "; 1138 1139} 1140 1141class OracleSchemaReader : SchemaReader 1142{ 1143 // SchemaReader.ReadSchema 1144 public override Tables ReadSchema(DbConnection connection, DbProviderFactory factory) 1145 { 1146 var result=new Tables(); 1147 1148 _connection=connection; 1149 _factory=factory; 1150 1151 var cmd=_factory.CreateCommand(); 1152 cmd.Connection=connection; 1153 cmd.CommandText=TABLE_SQL; 1154 cmd.GetType().GetProperty("BindByName").SetValue(cmd, true, null); 1155 1156 //pull the tables in a reader 1157 using(cmd) 1158 { 1159 1160 using (var rdr=cmd.ExecuteReader()) 1161 { 1162 while(rdr.Read()) 1163 { 1164 Table tbl=new Table(); 1165 tbl.Name=rdr["TABLE_NAME"].ToString(); 1166 tbl.Schema = rdr["TABLE_SCHEMA"].ToString(); 1167 tbl.IsView=string.Compare(rdr["TABLE_TYPE"].ToString(), "View", true)==0; 1168 tbl.CleanName=CleanUp(tbl.Name); 1169 tbl.ClassName=Inflector.MakeSingular(tbl.CleanName); 1170 result.Add(tbl); 1171 } 1172 } 1173 } 1174 1175 foreach (var tbl in result) 1176 { 1177 tbl.Columns=LoadColumns(tbl); 1178 1179 // Mark the primary key 1180 string PrimaryKey=GetPK(tbl.Name); 1181 var pkColumn=tbl.Columns.SingleOrDefault(x=>x.Name.ToLower().Trim()==PrimaryKey.ToLower().Trim()); 1182 if(pkColumn!=null) 1183 pkColumn.IsPK=true; 1184 } 1185 1186 1187 return result; 1188 } 1189 1190 DbConnection _connection; 1191 DbProviderFactory _factory; 1192 1193 1194 List<Column> LoadColumns(Table tbl) 1195 { 1196 1197 using (var cmd=_factory.CreateCommand()) 1198 { 1199 cmd.Connection=_connection; 1200 cmd.CommandText=COLUMN_SQL; 1201 cmd.GetType().GetProperty("BindByName").SetValue(cmd, true, null); 1202 1203 var p = cmd.CreateParameter(); 1204 p.ParameterName = ":tableName"; 1205 p.Value=tbl.Name; 1206 cmd.Parameters.Add(p); 1207 1208 var result=new List<Column>(); 1209 using (IDataReader rdr=cmd.ExecuteReader()) 1210 { 1211 while(rdr.Read()) 1212 { 1213 Column col=new Column(); 1214 col.Name=rdr["ColumnName"].ToString(); 1215 col.PropertyName=CleanUp(col.Name); 1216 col.PropertyType=GetPropertyType(rdr["DataType"].ToString(), (rdr["DataType"] == DBNull.Value ? null : rdr["DataType"].ToString())); 1217 col.IsNullable=rdr["IsNullable"].ToString()=="YES"; 1218 col.IsAutoIncrement=true; 1219 result.Add(col); 1220 } 1221 } 1222 1223 return result; 1224 } 1225 } 1226 1227 string GetPK(string table){ 1228 1229 string sql=@"select column_name from USER_CONSTRAINTS uc 1230 inner join USER_CONS_COLUMNS ucc on uc.constraint_name = ucc.constraint_name 1231where uc.constraint_type = 'P' 1232and uc.table_name = upper(:tableName) 1233and ucc.position = 1"; 1234 1235 using (var cmd=_factory.CreateCommand()) 1236 { 1237 cmd.Connection=_connection; 1238 cmd.CommandText=sql; 1239 cmd.GetType().GetProperty("BindByName").SetValue(cmd, true, null); 1240 1241 var p = cmd.CreateParameter(); 1242 p.ParameterName = ":tableName"; 1243 p.Value=table; 1244 cmd.Parameters.Add(p); 1245 1246 var result=cmd.ExecuteScalar(); 1247 1248 if(result!=null) 1249 return result.ToString(); 1250 } 1251 1252 return ""; 1253 } 1254 1255 string GetPropertyType(string sqlType, string dataScale) 1256 { 1257 string sysType="string"; 1258 switch (sqlType.ToLower()) 1259 { 1260 case "bigint": 1261 sysType = "long"; 1262 break; 1263 case "smallint": 1264 sysType= "short"; 1265 break; 1266 case "int": 1267 sysType= "int"; 1268 break; 1269 case "uniqueidentifier": 1270 sysType= "Guid"; 1271 break; 1272 case "smalldatetime": 1273 case "datetime": 1274 case "date": 1275 sysType= "DateTime"; 1276 break; 1277 case "float": 1278 sysType="double"; 1279 break; 1280 case "real": 1281 case "numeric": 1282 case "smallmoney": 1283 case "decimal": 1284 case "money": 1285 case "number": 1286 sysType= "decimal"; 1287 break; 1288 case "tinyint": 1289 sysType = "byte"; 1290 break; 1291 case "bit": 1292 sysType= "bool"; 1293 break; 1294 case "image": 1295 case "binary": 1296 case "varbinary": 1297 case "timestamp": 1298 sysType= "byte[]"; 1299 break; 1300 } 1301 1302 if (sqlType == "number" && dataScale == "0") 1303 return "long"; 1304 1305 return sysType; 1306 } 1307 1308 1309 1310 const string TABLE_SQL=@"select TABLE_NAME from USER_TABLES"; 1311 1312 const string COLUMN_SQL=@"select table_name TableName, 1313 column_name ColumnName, 1314 data_type DataType, 1315 data_scale DataScale, 1316 nullable IsNullable 1317 from USER_TAB_COLS utc 1318 where table_name = upper(:tableName) 1319 order by column_id"; 1320 1321} 1322 1323 1324 1325 1326/// <summary> 1327/// Summary for the Inflector class 1328/// </summary> 1329public static class Inflector { 1330 private static readonly List<InflectorRule> _plurals = new List<InflectorRule>(); 1331 private static readonly List<InflectorRule> _singulars = new List<InflectorRule>(); 1332 private static readonly List<string> _uncountables = new List<string>(); 1333 1334 /// <summary> 1335 /// Initializes the <see cref="Inflector"/> class. 1336 /// </summary> 1337 static Inflector() { 1338 AddPluralRule("$", "s"); 1339 AddPluralRule("s$", "s"); 1340 AddPluralRule("(ax|test)is$", "$1es"); 1341 AddPluralRule("(octop|vir)us$", "$1i"); 1342 AddPluralRule("(alias|status)$", "$1es"); 1343 AddPluralRule("(bu)s$", "$1ses"); 1344 AddPluralRule("(buffal|tomat)o$", "$1oes"); 1345 AddPluralRule("([ti])um$", "$1a"); 1346 AddPluralRule("sis$", "ses"); 1347 AddPluralRule("(?:([^f])fe|([lr])f)$", "$1$2ves"); 1348 AddPluralRule("(hive)$", "$1s"); 1349 AddPluralRule("([^aeiouy]|qu)y$", "$1ies"); 1350 AddPluralRule("(x|ch|ss|sh)$", "$1es"); 1351 AddPluralRule("(matr|vert|ind)ix|ex$", "$1ices"); 1352 AddPluralRule("([m|l])ouse$", "$1ice"); 1353 AddPluralRule("^(ox)$", "$1en"); 1354 AddPluralRule("(quiz)$", "$1zes"); 1355 1356 AddSingularRule("s$", String.Empty); 1357 AddSingularRule("ss$", "ss"); 1358 AddSingularRule("(n)ews$", "$1ews"); 1359 AddSingularRule("([ti])a$", "$1um"); 1360 AddSingularRule("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis"); 1361 AddSingularRule("(^analy)ses$", "$1sis"); 1362 AddSingularRule("([^f])ves$", "$1fe"); 1363 AddSingularRule("(hive)s$", "$1"); 1364 AddSingularRule("(tive)s$", "$1"); 1365 AddSingularRule("([lr])ves$", "$1f"); 1366 AddSingularRule("([^aeiouy]|qu)ies$", "$1y"); 1367 AddSingularRule("(s)eries$", "$1eries"); 1368 AddSingularRule("(m)ovies$", "$1ovie"); 1369 AddSingularRule("(x|ch|ss|sh)es$", "$1"); 1370 AddSingularRule("([m|l])ice$", "$1ouse"); 1371 AddSingularRule("(bus)es$", "$1"); 1372 AddSingularRule("(o)es$", "$1"); 1373 AddSingularRule("(shoe)s$", "$1"); 1374 AddSingularRule("(cris|ax|test)es$", "$1is"); 1375 AddSingularRule("(octop|vir)i$", "$1us"); 1376 AddSingularRule("(alias|status)$", "$1"); 1377 AddSingularRule("(alias|status)es$", "$1"); 1378 AddSingularRule("^(ox)en", "$1"); 1379 AddSingularRule("(vert|ind)ices$", "$1ex"); 1380 AddSingularRule("(matr)ices$", "$1ix"); 1381 AddSingularRule("(quiz)zes$", "$1"); 1382 1383 AddIrregularRule("person", "people"); 1384 AddIrregularRule("man", "men"); 1385 AddIrregularRule("child", "children"); 1386 AddIrregularRule("sex", "sexes"); 1387 AddIrregularRule("tax", "taxes"); 1388 AddIrregularRule("move", "moves"); 1389 1390 AddUnknownCountRule("equipment"); 1391 AddUnknownCountRule("information"); 1392 AddUnknownCountRule("rice"); 1393 AddUnknownCountRule("money"); 1394 AddUnknownCountRule("species"); 1395 AddUnknownCountRule("series"); 1396 AddUnknownCountRule("fish"); 1397 AddUnknownCountRule("sheep"); 1398 } 1399 1400 /// <summary> 1401 /// Adds the irregular rule. 1402 /// </summary> 1403 /// <param name="singular">The singular.</param> 1404 /// <param name="plural">The plural.</param> 1405 private static void AddIrregularRule(string singular, string plural) { 1406 AddPluralRule(String.Concat("(", singular[0], ")", singular.Substring(1), "$"), String.Concat("$1", plural.Substring(1))); 1407 AddSingularRule(String.Concat("(", plural[0], ")", plural.Substring(1), "$"), String.Concat("$1", singular.Substring(1))); 1408 } 1409 1410 /// <summary> 1411 /// Adds the unknown count rule. 1412 /// </summary> 1413 /// <param name="word">The word.</param> 1414 private static void AddUnknownCountRule(string word) { 1415 _uncountables.Add(word.ToLower()); 1416 } 1417 1418 /// <summary> 1419 /// Adds the plural rule. 1420 /// </summary> 1421 /// <param name="rule">The rule.</param> 1422 /// <param name="replacement">The replacement.</param> 1423 private static void AddPluralRule(string rule, string replacement) { 1424 _plurals.Add(new InflectorRule(rule, replacement)); 1425 } 1426 1427 /// <summary> 1428 /// Adds the singular rule. 1429 /// </summary> 1430 /// <param name="rule">The rule.</param> 1431 /// <param name="replacement">The replacement.</param> 1432 private static void AddSingularRule(string rule, string replacement) { 1433 _singulars.Add(new InflectorRule(rule, replacement)); 1434 } 1435 1436 /// <summary> 1437 /// Makes the plural. 1438 /// </summary> 1439 /// <param name="word">The word.</param> 1440 /// <returns></returns> 1441 public static string MakePlural(string word) { 1442 return ApplyRules(_plurals, word); 1443 } 1444 1445 /// <summary> 1446 /// Makes the singular. 1447 /// </summary> 1448 /// <param name="word">The word.</param> 1449 /// <returns></returns> 1450 public static string MakeSingular(string word) { 1451 return ApplyRules(_singulars, word); 1452 } 1453 1454 /// <summary> 1455 /// Applies the rules. 1456 /// </summary> 1457 /// <param name="rules">The rules.</param> 1458 /// <param name="word">The word.</param> 1459 /// <returns></returns> 1460 private static string ApplyRules(IList<InflectorRule> rules, string word) { 1461 string result = word; 1462 if (!_uncountables.Contains(word.ToLower())) { 1463 for (int i = rules.Count - 1; i >= 0; i--) { 1464 string currentPass = rules[i].Apply(word); 1465 if (currentPass != null) { 1466 result = currentPass; 1467 break; 1468 } 1469 } 1470 } 1471 return result; 1472 } 1473 1474 /// <summary> 1475 /// Converts the string to title case. 1476 /// </summary> 1477 /// <param name="word">The word.</param> 1478 /// <returns></returns> 1479 public static string ToTitleCase(string word) { 1480 return Regex.Replace(ToHumanCase(AddUnderscores(word)), @"\b([a-z])", 1481 delegate(Match match) { return match.Captures[0].Value.ToUpper(); }); 1482 } 1483 1484 /// <summary> 1485 /// Converts the string to human case. 1486 /// </summary> 1487 /// <param name="lowercaseAndUnderscoredWord">The lowercase and underscored word.</param> 1488 /// <returns></returns> 1489 public static string ToHumanCase(string lowercaseAndUnderscoredWord) { 1490 return MakeInitialCaps(Regex.Replace(lowercaseAndUnderscoredWord, @"_", " ")); 1491 } 1492 1493 1494 /// <summary> 1495 /// Adds the underscores. 1496 /// </summary> 1497 /// <param name="pascalCasedWord">The pascal cased word.</param> 1498 /// <returns></returns> 1499 public static string AddUnderscores(string pascalCasedWord) { 1500 return Regex.Replace(Regex.Replace(Regex.Replace(pascalCasedWord, @"([A-Z]+)([A-Z][a-z])", "$1_$2"), @"([a-z\d])([A-Z])", "$1_$2"), @"[-\s]", "_").ToLower(); 1501 } 1502 1503 /// <summary> 1504 /// Makes the initial caps. 1505 /// </summary> 1506 /// <param name="word">The word.</param> 1507 /// <returns></returns> 1508 public static string MakeInitialCaps(string word) { 1509 return String.Concat(word.Substring(0, 1).ToUpper(), word.Substring(1).ToLower()); 1510 } 1511 1512 /// <summary> 1513 /// Makes the initial lower case. 1514 /// </summary> 1515 /// <param name="word">The word.</param> 1516 /// <returns></returns> 1517 public static string MakeInitialLowerCase(string word) { 1518 return String.Concat(word.Substring(0, 1).ToLower(), word.Substring(1)); 1519 } 1520 1521 1522 /// <summary> 1523 /// Determine whether the passed string is numeric, by attempting to parse it to a double 1524 /// </summary> 1525 /// <param name="str">The string to evaluated for numeric conversion</param> 1526 /// <returns> 1527 /// <c>true</c> if the string can be converted to a number; otherwise, <c>false</c>. 1528 /// </returns> 1529 public static bool IsStringNumeric(string str) { 1530 double result; 1531 return (double.TryParse(str, NumberStyles.Float, NumberFormatInfo.CurrentInfo, out result)); 1532 } 1533 1534 /// <summary> 1535 /// Adds the ordinal suffix. 1536 /// </summary> 1537 /// <param name="number">The number.</param> 1538 /// <returns></returns> 1539 public static string AddOrdinalSuffix(string number) { 1540 if (IsStringNumeric(number)) { 1541 int n = int.Parse(number); 1542 int nMod100 = n % 100; 1543 1544 if (nMod100 >= 11 && nMod100 <= 13) 1545 return String.Concat(number, "th"); 1546 1547 switch (n % 10) { 1548 case 1: 1549 return String.Concat(number, "st"); 1550 case 2: 1551 return String.Concat(number, "nd"); 1552 case 3: 1553 return String.Concat(number, "rd"); 1554 default: 1555 return String.Concat(number, "th"); 1556 } 1557 } 1558 return number; 1559 } 1560 1561 /// <summary> 1562 /// Converts the underscores to dashes. 1563 /// </summary> 1564 /// <param name="underscoredWord">The underscored word.</param> 1565 /// <returns></returns> 1566 public static string ConvertUnderscoresToDashes(string underscoredWord) { 1567 return underscoredWord.Replace('_', '-'); 1568 } 1569 1570 1571 #region Nested type: InflectorRule 1572 1573 /// <summary> 1574 /// Summary for the InflectorRule class 1575 /// </summary> 1576 private class InflectorRule { 1577 /// <summary> 1578 /// 1579 /// </summary> 1580 public readonly Regex regex; 1581 1582 /// <summary> 1583 /// 1584 /// </summary> 1585 public readonly string replacement; 1586 1587 /// <summary> 1588 /// Initializes a new instance of the <see cref="InflectorRule"/> class. 1589 /// </summary> 1590 /// <param name="regexPattern">The regex pattern.</param> 1591 /// <param name="replacementText">The replacement text.</param> 1592 public InflectorRule(string regexPattern, string replacementText) { 1593 regex = new Regex(regexPattern, RegexOptions.IgnoreCase); 1594 replacement = replacementText; 1595 } 1596 1597 /// <summary> 1598 /// Applies the specified word. 1599 /// </summary> 1600 /// <param name="word">The word.</param> 1601 /// <returns></returns> 1602 public string Apply(string word) { 1603 if (!regex.IsMatch(word)) 1604 return null; 1605 1606 string replace = regex.Replace(word, replacement); 1607 if (word == word.ToUpper()) 1608 replace = replace.ToUpper(); 1609 1610 return replace; 1611 } 1612 } 1613 1614 #endregion 1615} 1616 1617#>