Commit c52cc697 authored by Sam Saffron's avatar Sam Saffron

merge

parents 536fed0d 2dfa6423
......@@ -98,8 +98,27 @@ public void Run(int iterations)
var massiveConnection = Program.GetOpenConnection();
tests.Add(id => massiveModel.Query("select * from Posts where Id = @0", massiveConnection, id).ToList(), "Dynamic Massive ORM Query");
// HAND CODED
// PetaPoco test with all default options
var petapoco = new PetaPoco.Database(Program.connectionString, "System.Data.SqlClient");
petapoco.OpenSharedConnection();
tests.Add(id => petapoco.Fetch<Post>("SELECT * from Posts where Id=@0", id), "PetaPoco (Normal)");
// PetaPoco with some "smart" functionality disabled
var petapocoFast = new PetaPoco.Database(Program.connectionString, "System.Data.SqlClient");
petapocoFast.OpenSharedConnection();
petapocoFast.EnableAutoSelect = false;
petapocoFast.EnableNamedParams = false;
petapocoFast.ForceDateTimesToUtc = false;
tests.Add(id => petapocoFast.Fetch<Post>("SELECT * from Posts where Id=@0", id), "PetaPoco (Fast)");
// Subsonic ActiveRecord
tests.Add(id => SubSonic.Post.SingleOrDefault(x => x.Id == id), "SubSonic ActiveRecord.SingleOrDefault");
// Subsonic ActiveRecord
SubSonic.tempdbDB db=new SubSonic.tempdbDB();
tests.Add(id => new SubSonic.Query.CodingHorror(db.Provider, "select * from Posts where Id = @0", id).ExecuteTypedList<Post>(), "SubSonic Coding Horror");
// HAND CODED
var connection = Program.GetOpenConnection();
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Data.Common;
using System.Data;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Reflection.Emit;
namespace PetaPoco
{
// Poco's marked [Explicit] require all column properties to be marked
[AttributeUsage(AttributeTargets.Class)]
public class ExplicitColumns : Attribute
{
}
// For non-explicit pocos, causes a property to be ignored
[AttributeUsage(AttributeTargets.Property)]
public class Ignore : Attribute
{
}
// For explicit pocos, marks property as a column and optionally supplies column name
[AttributeUsage(AttributeTargets.Property)]
public class Column : Attribute
{
public Column() { }
public Column(string name) { Name = name; }
public string Name { get; set; }
}
// For explicit pocos, marks property as a result column and optionally supplies column name
[AttributeUsage(AttributeTargets.Property)]
public class ResultColumn : Column
{
public ResultColumn() { }
public ResultColumn(string name) : base(name) { }
}
// Specify the table name of a poco
[AttributeUsage(AttributeTargets.Class)]
public class TableName : Attribute
{
public TableName(string tableName)
{
Value = tableName;
}
public string Value { get; private set; }
}
// Specific the primary key of a poco class
[AttributeUsage(AttributeTargets.Class)]
public class PrimaryKey : Attribute
{
public PrimaryKey(string primaryKey)
{
Value = primaryKey;
}
public string Value { get; private set; }
}
// Results from paged request
public class Page<T> where T : new()
{
public long CurrentPage { get; set; }
public long TotalPages { get; set; }
public long TotalItems { get; set; }
public long ItemsPerPage { get; set; }
public List<T> Items { get; set; }
}
// Optionally provide and implementation of this to Database.Mapper
public interface IMapper
{
void GetTableInfo(Type t, ref string tableName, ref string primaryKey);
bool MapPropertyToColumn(PropertyInfo pi, ref string columnName, ref bool resultColumn);
Func<object, object> GetValueConverter(PropertyInfo pi, Type SourceType);
}
// Database class ... this is where most of the action happens
public class Database : IDisposable
{
public Database(DbConnection connection)
{
_sharedConnection = connection;
_connectionString = connection.ConnectionString;
_sharedConnectionDepth = 2; // Prevent closing external connection
CommonConstruct();
}
public Database(string connectionString, string providerName)
{
_connectionString = connectionString;
_providerName = providerName;
CommonConstruct();
}
public Database(string connectionStringName)
{
// Use first?
if (connectionStringName == "")
connectionStringName = ConfigurationManager.ConnectionStrings[0].Name;
// Work out connection string and provider name
var providerName = "System.Data.SqlClient";
if (ConfigurationManager.ConnectionStrings[connectionStringName] != null)
{
if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName))
providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;
}
else
{
throw new InvalidOperationException("Can't find a connection string with the name '" + connectionStringName + "'");
}
// Store factory and connection string
_connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
_providerName = providerName;
CommonConstruct();
}
// Common initialization
void CommonConstruct()
{
_transactionDepth = 0;
EnableAutoSelect = true;
EnableNamedParams = true;
ForceDateTimesToUtc = true;
if (_providerName != null)
_factory = DbProviderFactories.GetFactory(_providerName);
if (_connectionString != null && _connectionString.IndexOf("Allow User Variables=true") >= 0 && IsMySql())
_paramPrefix = "?";
}
// Automatically close one open shared connection
public void Dispose()
{
if (_sharedConnectionDepth > 0)
CloseSharedConnection();
}
// Who are we talking too?
bool IsMySql() { return string.Compare(_providerName, "MySql.Data.MySqlClient", true) == 0; }
bool IsSqlServer() { return string.Compare(_providerName, "System.Data.SqlClient", true) == 0; }
// Open a connection (can be nested)
public void OpenSharedConnection()
{
if (_sharedConnectionDepth == 0)
{
_sharedConnection = _factory.CreateConnection();
_sharedConnection.ConnectionString = _connectionString;
_sharedConnection.Open();
}
_sharedConnectionDepth++;
}
// Close a previously opened connection
public void CloseSharedConnection()
{
_sharedConnectionDepth--;
if (_sharedConnectionDepth == 0)
{
_sharedConnection.Dispose();
_sharedConnection = null;
}
}
// Helper to create a transaction scope
public Transaction Transaction
{
get
{
return new Transaction(this);
}
}
// Use by derived repo generated by T4 templates
public virtual void OnBeginTransaction() { }
public virtual void OnEndTransaction() { }
// Start a new transaction, can be nested, every call must be
// matched by a call to AbortTransaction or CompleteTransaction
// Use `using (var scope=db.Transaction) { scope.Complete(); }` to ensure correct semantics
public void BeginTransaction()
{
_transactionDepth++;
if (_transactionDepth == 1)
{
OpenSharedConnection();
_transaction = _sharedConnection.BeginTransaction();
_transactionCancelled = false;
OnBeginTransaction();
}
}
// Internal helper to cleanup transaction stuff
void CleanupTransaction()
{
OnEndTransaction();
if (_transactionCancelled)
_transaction.Rollback();
else
_transaction.Commit();
_transaction.Dispose();
_transaction = null;
CloseSharedConnection();
}
// Abort the entire outer most transaction scope
public void AbortTransaction()
{
_transactionCancelled = true;
if ((--_transactionDepth) == 0)
CleanupTransaction();
}
// Complete the transaction
public void CompleteTransaction()
{
if ((--_transactionDepth) == 0)
CleanupTransaction();
}
// Helper to handle named parameters from object properties
static Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
public static string ProcessParams(string _sql, object[] args_src, List<object> args_dest)
{
return rxParams.Replace(_sql, m =>
{
string param = m.Value.Substring(1);
int paramIndex;
if (int.TryParse(param, out paramIndex))
{
// Numbered parameter
if (paramIndex < 0 || paramIndex >= args_src.Length)
throw new ArgumentOutOfRangeException(string.Format("Parameter '@{0}' specified but only {1} parameters supplied (in `{2}`)", paramIndex, args_src.Length, _sql));
args_dest.Add(args_src[paramIndex]);
}
else
{
// Look for a property on one of the arguments with this name
bool found = false;
foreach (var o in args_src)
{
var pi = o.GetType().GetProperty(param);
if (pi != null)
{
args_dest.Add(pi.GetValue(o, null));
found = true;
break;
}
}
if (!found)
throw new ArgumentException(string.Format("Parameter '@{0}' specified but none of the passed arguments have a property with this name (in '{1}')", param, _sql));
}
return "@" + (args_dest.Count - 1).ToString();
}
);
}
// Add a parameter to a DB command
static void AddParam(DbCommand cmd, object item, string ParameterPrefix)
{
var p = cmd.CreateParameter();
p.ParameterName = string.Format("{0}{1}", ParameterPrefix, cmd.Parameters.Count);
if (item == null)
{
p.Value = DBNull.Value;
}
else
{
if (item.GetType() == typeof(Guid))
{
p.Value = item.ToString();
p.DbType = DbType.String;
p.Size = 4000;
}
else if (item.GetType() == typeof(string))
{
p.Size = (item as string).Length + 1;
if (p.Size < 4000)
p.Size = 4000;
p.Value = item;
}
else
{
p.Value = item;
}
}
cmd.Parameters.Add(p);
}
// Create a command
public DbCommand CreateCommand(DbConnection connection, string sql, params object[] args)
{
if (EnableNamedParams)
{
// Perform named argument replacements
var new_args = new List<object>();
sql = ProcessParams(sql, args, new_args);
args = new_args.ToArray();
}
// If we're in MySQL "Allow User Variables", we need to fix up parameter prefixes
if (_paramPrefix == "?")
{
// Convert "@parameter" -> "?parameter"
Regex paramReg = new Regex(@"(?<!@)@\w+");
sql = paramReg.Replace(sql, m => "?" + m.Value.Substring(1));
// Convert @@uservar -> @uservar and @@@systemvar -> @@systemvar
sql = sql.Replace("@@", "@");
}
// Save the last sql and args
_lastSql = sql;
_lastArgs = args;
DbCommand cmd = connection.CreateCommand();
cmd.CommandText = sql;
cmd.Transaction = _transaction;
foreach (var item in args)
{
var p = cmd.CreateParameter();
p.ParameterName = string.Format("{0}{1}", _paramPrefix, cmd.Parameters.Count);
if (item == null)
{
p.Value = DBNull.Value;
}
else
{
if (item.GetType() == typeof(Guid))
{
p.Value = item.ToString();
p.DbType = DbType.String;
p.Size = 4000;
}
else if (item.GetType() == typeof(string))
{
p.Size = (item as string).Length + 1;
if (p.Size < 4000)
p.Size = 4000;
p.Value = item;
}
else
{
p.Value = item;
}
}
cmd.Parameters.Add(p);
}
return cmd;
}
// Override this to log/capture exceptions
public virtual void OnException(Exception x)
{
System.Diagnostics.Debug.WriteLine(x.ToString());
System.Diagnostics.Debug.WriteLine(LastCommand);
}
// Execute a non-query command
public int Execute(string sql, params object[] args)
{
try
{
OpenSharedConnection();
try
{
using (var cmd = CreateCommand(_sharedConnection, sql, args))
{
return cmd.ExecuteNonQuery();
}
}
finally
{
CloseSharedConnection();
}
}
catch (Exception x)
{
OnException(x);
throw;
}
}
public int Execute(Sql sql)
{
return Execute(sql.SQL, sql.Arguments);
}
// Execute and cast a scalar property
public T ExecuteScalar<T>(string sql, params object[] args)
{
try
{
OpenSharedConnection();
try
{
using (var cmd = CreateCommand(_sharedConnection, sql, args))
{
object val = cmd.ExecuteScalar();
return (T)Convert.ChangeType(val, typeof(T));
}
}
finally
{
CloseSharedConnection();
}
}
catch (Exception x)
{
OnException(x);
throw;
}
}
public T ExecuteScalar<T>(Sql sql)
{
return ExecuteScalar<T>(sql.SQL, sql.Arguments);
}
Regex rxSelect = new Regex(@"^\s*SELECT\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
string AddSelectClause<T>(string sql)
{
// Already present?
if (rxSelect.IsMatch(sql))
return sql;
// Get the poco data for this type
var pd = PocoData.ForType(typeof(T));
return string.Format("SELECT {0} FROM {1} {2}", pd.QueryColumns, pd.TableName, sql);
}
public bool EnableAutoSelect { get; set; }
public bool EnableNamedParams { get; set; }
public bool ForceDateTimesToUtc { get; set; }
// Return a typed list of pocos
public List<T> Fetch<T>(string sql, params object[] args) where T : new()
{
// Auto select clause?
if (EnableAutoSelect)
sql = AddSelectClause<T>(sql);
try
{
OpenSharedConnection();
try
{
using (var cmd = CreateCommand(_sharedConnection, sql, args))
{
using (var r = cmd.ExecuteReader())
{
var l = new List<T>();
var pd = PocoData.ForType(typeof(T));
var factory = pd.GetFactory<T>(sql + "-" + _sharedConnection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r);
while (r.Read())
{
l.Add(factory(r));
}
return l;
}
}
}
finally
{
CloseSharedConnection();
}
}
catch (Exception x)
{
OnException(x);
throw;
}
}
// Optimized version when only needing a single record
public T FirstOrDefault<T>(string sql, params object[] args) where T : new()
{
// Auto select clause?
if (EnableAutoSelect)
sql = AddSelectClause<T>(sql);
try
{
OpenSharedConnection();
try
{
using (var cmd = CreateCommand(_sharedConnection, sql, args))
{
using (var r = cmd.ExecuteReader())
{
if (!r.Read())
return default(T);
var pd = PocoData.ForType(typeof(T));
var factory = pd.GetFactory<T>(sql + "-" + _sharedConnection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r);
return factory(r);
}
}
}
finally
{
CloseSharedConnection();
}
}
catch (Exception x)
{
OnException(x);
throw;
}
}
// Optimized version when only wanting a single record
public T SingleOrDefault<T>(string sql, params object[] args) where T : new()
{
// Auto select clause?
if (EnableAutoSelect)
sql = AddSelectClause<T>(sql);
try
{
OpenSharedConnection();
try
{
using (var cmd = CreateCommand(_sharedConnection, sql, args))
{
using (var r = cmd.ExecuteReader())
{
if (!r.Read())
return default(T);
var pd = PocoData.ForType(typeof(T));
var factory = pd.GetFactory<T>(sql + "-" + _sharedConnection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r);
T ret = factory(r);
if (r.Read())
throw new InvalidOperationException("Sequence contains more than one element");
return ret;
}
}
}
finally
{
CloseSharedConnection();
}
}
catch (Exception x)
{
OnException(x);
throw;
}
}
// Warning: scary regex follows
static Regex rxColumns = new Regex(@"^\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b",
RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*",
RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
{
sqlSelectRemoved = null;
sqlCount = null;
sqlOrderBy = null;
// Extract the columns from "SELECT <whatever> FROM"
var m = rxColumns.Match(sql);
if (!m.Success)
return false;
// Save column list and replace with COUNT(*)
Group g = m.Groups[1];
sqlCount = sql.Substring(0, g.Index) + "COUNT(*) " + sql.Substring(g.Index + g.Length);
sqlSelectRemoved = sql.Substring(g.Index);
// Look for an "ORDER BY <whatever>" clause
m = rxOrderBy.Match(sqlCount);
if (!m.Success)
return false;
g = m.Groups[0];
sqlOrderBy = g.ToString();
sqlCount = sqlCount.Substring(0, g.Index) + sqlCount.Substring(g.Index + g.Length);
return true;
}
// Fetch a page
public Page<T> Page<T>(long page, long itemsPerPage, string sql, params object[] args) where T : new()
{
// Add auto select clause
if (EnableAutoSelect)
sql = AddSelectClause<T>(sql);
// Split the SQL into the bits we need
string sqlCount, sqlSelectRemoved, sqlOrderBy;
if (!SplitSqlForPaging(sql, out sqlCount, out sqlSelectRemoved, out sqlOrderBy))
throw new Exception("Unable to parse SQL statement for paged query");
// Setup the paged result
var result = new Page<T>();
result.CurrentPage = page;
result.ItemsPerPage = itemsPerPage;
result.TotalItems = ExecuteScalar<long>(sqlCount, args);
result.TotalPages = result.TotalItems / itemsPerPage;
if ((result.TotalItems % itemsPerPage) != 0)
result.TotalPages++;
// Build the SQL for the actual final result
string sqlPage;
if (IsSqlServer())
{
// Ugh really?
sqlSelectRemoved = rxOrderBy.Replace(sqlSelectRemoved, "");
sqlPage = string.Format("SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) AS __rn, {1}) as __paged WHERE __rn>{2} AND __rn<={3}",
sqlOrderBy, sqlSelectRemoved, (page - 1) * itemsPerPage, page * itemsPerPage);
}
else
{
// Nice
sqlPage = string.Format("{0}\nLIMIT {1} OFFSET {2}", sql, itemsPerPage, (page - 1) * itemsPerPage);
}
// Get the records
result.Items = Fetch<T>(sqlPage, args);
// Done
return result;
}
public Page<T> Page<T>(long page, long itemsPerPage, Sql sql) where T : new()
{
return Page<T>(page, itemsPerPage, sql.SQL, sql.Arguments);
}
// Return an enumerable collection of pocos
public IEnumerable<T> Query<T>(string sql, params object[] args) where T : new()
{
if (EnableAutoSelect)
sql = AddSelectClause<T>(sql);
using (var conn = new ShareableConnection(this))
{
using (var cmd = CreateCommand(conn.Connection, sql, args))
{
IDataReader r;
var pd = PocoData.ForType(typeof(T));
try
{
r = cmd.ExecuteReader();
}
catch (Exception x)
{
OnException(x);
throw;
}
var factory = pd.GetFactory<T>(sql + "-" + conn.Connection.ConnectionString + ForceDateTimesToUtc.ToString(), ForceDateTimesToUtc, r);
using (r)
{
while (true)
{
T poco;
try
{
if (!r.Read())
yield break;
poco = factory(r);
}
catch (Exception x)
{
OnException(x);
throw;
}
yield return poco;
}
}
}
}
}
public List<T> Fetch<T>(Sql sql) where T : new()
{
return Fetch<T>(sql.SQL, sql.Arguments);
}
public IEnumerable<T> Query<T>(Sql sql) where T : new()
{
return Query<T>(sql.SQL, sql.Arguments);
}
public T Single<T>(string sql, params object[] args) where T : new()
{
T val = SingleOrDefault<T>(sql, args);
if (val != null)
return val;
else
throw new InvalidOperationException("The sequence contains no elements");
}
public T First<T>(string sql, params object[] args) where T : new()
{
T val = FirstOrDefault<T>(sql, args);
if (val != null)
return val;
else
throw new InvalidOperationException("The sequence contains no elements");
}
public T Single<T>(Sql sql) where T : new()
{
return Single<T>(sql.SQL, sql.Arguments);
}
public T SingleOrDefault<T>(Sql sql) where T : new()
{
return SingleOrDefault<T>(sql.SQL, sql.Arguments);
}
public T FirstOrDefault<T>(Sql sql) where T : new()
{
return FirstOrDefault<T>(sql.SQL, sql.Arguments);
}
public T First<T>(Sql sql) where T : new()
{
return First<T>(sql.SQL, sql.Arguments);
}
// Insert a poco into a table. If the poco has a property with the same name
// as the primary key the id of the new record is assigned to it. Either way,
// the new id is returned.
public object Insert(string tableName, string primaryKeyName, object poco)
{
try
{
OpenSharedConnection();
try
{
using (var cmd = CreateCommand(_sharedConnection, ""))
{
var pd = PocoData.ForType(poco.GetType());
var names = new List<string>();
var values = new List<string>();
var index = 0;
foreach (var i in pd.Columns)
{
// Don't insert the primary key or result only columns
if ((primaryKeyName != null && i.Key == primaryKeyName) || i.Value.ResultColumn)
continue;
names.Add(i.Key);
values.Add(string.Format("{0}{1}", _paramPrefix, index++));
AddParam(cmd, i.Value.PropertyInfo.GetValue(poco, null), _paramPrefix);
}
cmd.CommandText = string.Format("INSERT INTO {0} ({1}) VALUES ({2}); SELECT @@IDENTITY AS NewID;",
tableName,
string.Join(",", names.ToArray()),
string.Join(",", values.ToArray())
);
_lastSql = cmd.CommandText;
_lastArgs = values.ToArray();
// Insert the record, should get back it's ID
var id = cmd.ExecuteScalar();
// Assign the ID back to the primary key property
if (primaryKeyName != null)
{
PocoColumn pc;
if (pd.Columns.TryGetValue(primaryKeyName, out pc))
{
pc.PropertyInfo.SetValue(poco, Convert.ChangeType(id, pc.PropertyInfo.PropertyType), null);
}
}
return id;
}
}
finally
{
CloseSharedConnection();
}
}
catch (Exception x)
{
OnException(x);
throw;
}
}
// Insert an annotated poco object
public object Insert(object poco)
{
var pd = PocoData.ForType(poco.GetType());
return Insert(pd.TableName, pd.PrimaryKey, poco);
}
// Update a record with values from a poco. primary key value can be either supplied or read from the poco
public int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue)
{
try
{
OpenSharedConnection();
try
{
using (var cmd = CreateCommand(_sharedConnection, ""))
{
var sb = new StringBuilder();
var index = 0;
var pd = PocoData.ForType(poco.GetType());
foreach (var i in pd.Columns)
{
// Don't update the primary key, but grab the value if we don't have it
if (i.Key == primaryKeyName)
{
if (primaryKeyValue == null)
primaryKeyValue = i.Value.PropertyInfo.GetValue(poco, null);
continue;
}
// Dont update result only columns
if (i.Value.ResultColumn)
continue;
// Build the sql
if (index > 0)
sb.Append(", ");
sb.AppendFormat("{0} = {1}{2}", i.Key, _paramPrefix, index++);
// Store the parameter in the command
AddParam(cmd, i.Value.PropertyInfo.GetValue(poco, null), _paramPrefix);
}
cmd.CommandText = string.Format("UPDATE {0} SET {1} WHERE {2} = {3}{4}",
tableName,
sb.ToString(),
primaryKeyName,
_paramPrefix,
index++
);
AddParam(cmd, primaryKeyValue, _paramPrefix);
_lastSql = cmd.CommandText;
_lastArgs = new object[] { primaryKeyValue };
// Do it
return cmd.ExecuteNonQuery();
}
}
finally
{
CloseSharedConnection();
}
}
catch (Exception x)
{
OnException(x);
throw;
}
}
public int Update(string tableName, string primaryKeyName, object poco)
{
return Update(tableName, primaryKeyName, poco, null);
}
public int Update(object poco)
{
return Update(poco, null);
}
public int Update(object poco, object primaryKeyValue)
{
var pd = PocoData.ForType(poco.GetType());
return Update(pd.TableName, pd.PrimaryKey, poco, primaryKeyValue);
}
public int Update<T>(string sql, params object[] args)
{
var pd = PocoData.ForType(typeof(T));
return Execute(string.Format("UPDATE {0} {1}", pd.TableName, sql), args);
}
public int Update<T>(Sql sql)
{
var pd = PocoData.ForType(typeof(T));
return Execute(new Sql(string.Format("UPDATE {0}", pd.TableName)).Append(sql));
}
public int Delete(string tableName, string primaryKeyName, object poco)
{
return Delete(tableName, primaryKeyName, poco, null);
}
public int Delete(string tableName, string primaryKeyName, object poco, object primaryKeyValue)
{
// If primary key value not specified, pick it up from the object
if (primaryKeyValue == null)
{
var pd = PocoData.ForType(poco.GetType());
PocoColumn pc;
if (pd.Columns.TryGetValue(primaryKeyName, out pc))
{
primaryKeyValue = pc.PropertyInfo.GetValue(poco, null);
}
}
// Do it
var sql = string.Format("DELETE FROM {0} WHERE {1}=@0", tableName, primaryKeyName);
return Execute(sql, primaryKeyValue);
}
public int Delete(object poco)
{
var pd = PocoData.ForType(poco.GetType());
return Delete(pd.TableName, pd.PrimaryKey, poco);
}
public int Delete<T>(string sql, params object[] args)
{
var pd = PocoData.ForType(typeof(T));
return Execute(string.Format("DELETE FROM {0} {1}", pd.TableName, sql), args);
}
public int Delete<T>(Sql sql)
{
var pd = PocoData.ForType(typeof(T));
return Execute(new Sql(string.Format("DELETE FROM {0}", pd.TableName)).Append(sql));
}
// Check if a poco represents a new record
public bool IsNew(string primaryKeyName, object poco)
{
// If primary key value not specified, pick it up from the object
var pd = PocoData.ForType(poco.GetType());
PropertyInfo pi;
PocoColumn pc;
if (pd.Columns.TryGetValue(primaryKeyName, out pc))
{
pi = pc.PropertyInfo;
}
else
{
pi = poco.GetType().GetProperty(primaryKeyName);
if (pi == null)
throw new ArgumentException("The object doesn't have a property matching the primary key column name '{0}'", primaryKeyName);
}
// Get it's value
var pk = pi.GetValue(poco, null);
if (pk == null)
return true;
var type = pk.GetType();
if (type.IsValueType)
{
// Common primary key types
if (type == typeof(long))
return (long)pk == 0;
else if (type == typeof(ulong))
return (ulong)pk == 0;
else if (type == typeof(int))
return (int)pk == 0;
else if (type == typeof(uint))
return (int)pk == 0;
// Create a default instance and compare
return pk == Activator.CreateInstance(pk.GetType());
}
else
{
return pk == null;
}
}
public bool IsNew(object poco)
{
var pd = PocoData.ForType(poco.GetType());
return IsNew(pd.PrimaryKey, poco);
}
// Insert new record or Update existing record
public void Save(string tableName, string primaryKeyName, object poco)
{
if (IsNew(primaryKeyName, poco))
{
Insert(tableName, primaryKeyName, poco);
}
else
{
Update(tableName, primaryKeyName, poco);
}
}
public void Save(object poco)
{
var pd = PocoData.ForType(poco.GetType());
Save(pd.TableName, pd.PrimaryKey, poco);
}
public string LastSQL { get { return _lastSql; } }
public object[] LastArgs { get { return _lastArgs; } }
public string LastCommand
{
get
{
var sb = new StringBuilder();
if (_lastSql == null)
return "";
sb.Append(_lastSql);
if (_lastArgs != null)
{
sb.Append("\r\n\r\n");
for (int i = 0; i < _lastArgs.Length; i++)
{
sb.AppendFormat("{0} - {1}\r\n", i, _lastArgs[i].ToString());
}
}
return sb.ToString();
}
}
public static IMapper Mapper
{
get;
set;
}
internal class PocoColumn
{
public string ColumnName;
public PropertyInfo PropertyInfo;
public bool ResultColumn;
}
internal class PocoData
{
public static PocoData ForType(Type t)
{
lock (m_PocoData)
{
PocoData pd;
if (!m_PocoData.TryGetValue(t, out pd))
{
pd = new PocoData(t);
m_PocoData.Add(t, pd);
}
return pd;
}
}
public PocoData(Type t)
{
// Get the table name
var a = t.GetCustomAttributes(typeof(TableName), true);
var tempTableName = a.Length == 0 ? t.Name : (a[0] as TableName).Value;
// Get the primary key
a = t.GetCustomAttributes(typeof(PrimaryKey), true);
var tempPrimaryKey = a.Length == 0 ? "ID" : (a[0] as PrimaryKey).Value;
// Call column mapper
if (Database.Mapper != null)
Database.Mapper.GetTableInfo(t, ref tempTableName, ref tempPrimaryKey);
TableName = tempTableName;
PrimaryKey = tempPrimaryKey;
// Work out bound properties
bool ExplicitColumns = t.GetCustomAttributes(typeof(ExplicitColumns), true).Length > 0;
Columns = new Dictionary<string, PocoColumn>(StringComparer.OrdinalIgnoreCase);
foreach (var pi in t.GetProperties())
{
// Work out if properties is to be included
var ColAttrs = pi.GetCustomAttributes(typeof(Column), true);
if (ExplicitColumns)
{
if (ColAttrs.Length == 0)
continue;
}
else
{
if (pi.GetCustomAttributes(typeof(Ignore), true).Length != 0)
continue;
}
var pc = new PocoColumn();
pc.PropertyInfo = pi;
// Work out the DB column name
if (ColAttrs.Length > 0)
{
var colattr = (Column)ColAttrs[0];
pc.ColumnName = colattr.Name;
if ((colattr as ResultColumn) != null)
pc.ResultColumn = true;
}
if (pc.ColumnName == null)
{
pc.ColumnName = pi.Name;
if (Database.Mapper != null && !Database.Mapper.MapPropertyToColumn(pi, ref pc.ColumnName, ref pc.ResultColumn))
continue;
}
// Store it
Columns.Add(pc.ColumnName, pc);
}
// Build column list for automatic select
QueryColumns = string.Join(", ", (from c in Columns where !c.Value.ResultColumn select c.Key).ToArray());
}
// Create factory function that can convert a IDataReader record into a POCO
public Func<IDataReader, T> GetFactory<T>(string key, bool ForceDateTimesToUtc, IDataReader r)
{
lock (PocoFactories)
{
// Have we already created it?
object factory;
if (PocoFactories.TryGetValue(key, out factory))
return factory as Func<IDataReader, T>;
lock (m_Converters)
{
// Create the method
var m = new DynamicMethod("petapoco_factory_" + PocoFactories.Count.ToString(), typeof(T), new Type[] { typeof(IDataReader) }, true);
var il = m.GetILGenerator();
// Running under mono?
int p = (int)Environment.OSVersion.Platform;
bool Mono = (p == 4) || (p == 6) || (p == 128);
// var poco=new T()
il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes));
// Enumerate all fields generating a set assignment for the column
for (int i = 0; i < r.FieldCount; i++)
{
// Get the PocoColumn for this db column, ignore if not known
PocoColumn pc;
if (!Columns.TryGetValue(r.GetName(i), out pc))
continue;
// Get the source type for this column
var srcType = r.GetFieldType(i);
var dstType = pc.PropertyInfo.PropertyType;
// "if (!rdr.IsDBNull(i))"
il.Emit(OpCodes.Ldarg_0); // poco,rdr
il.Emit(OpCodes.Ldc_I4, i); // poco,rdr,i
il.Emit(OpCodes.Callvirt, fnIsDBNull); // poco,bool
var lblNext = il.DefineLabel();
il.Emit(OpCodes.Brtrue_S, lblNext); // poco
il.Emit(OpCodes.Dup); // poco,poco
// Do we need to install a converter?
Func<object, object> converter = null;
// Get converter from the mapper
if (Database.Mapper != null)
{
converter = Database.Mapper.GetValueConverter(pc.PropertyInfo, srcType);
}
// Standard DateTime->Utc mapper
if (ForceDateTimesToUtc && converter == null && srcType == typeof(DateTime) && (dstType == typeof(DateTime) || dstType == typeof(DateTime?)))
{
converter = delegate(object src) { return new DateTime(((DateTime)src).Ticks, DateTimeKind.Utc); };
}
// Forced type conversion
if (converter == null && !dstType.IsAssignableFrom(srcType))
{
converter = delegate(object src) { return Convert.ChangeType(src, dstType, null); };
}
// Fast
bool Handled = false;
if (converter == null)
{
var valuegetter = typeof(IDataRecord).GetMethod("Get" + srcType.Name, new Type[] { typeof(int) });
if (valuegetter != null
&& valuegetter.ReturnType == srcType
&& (valuegetter.ReturnType == dstType || valuegetter.ReturnType == Nullable.GetUnderlyingType(dstType)))
{
il.Emit(OpCodes.Ldarg_0); // *,rdr
il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i
il.Emit(OpCodes.Callvirt, valuegetter); // *,value
// Mono give IL error if we don't explicitly create Nullable instance for the assignment
if (Mono && Nullable.GetUnderlyingType(dstType) != null)
{
il.Emit(OpCodes.Newobj, dstType.GetConstructor(new Type[] { Nullable.GetUnderlyingType(dstType) }));
}
il.Emit(OpCodes.Callvirt, pc.PropertyInfo.GetSetMethod()); // poco
Handled = true;
}
}
// Not so fast
if (!Handled)
{
// Setup stack for call to converter
int converterIndex = -1;
if (converter != null)
{
// Add the converter
converterIndex = m_Converters.Count;
m_Converters.Add(converter);
// Generate IL to push the converter onto the stack
il.Emit(OpCodes.Ldsfld, fldConverters);
il.Emit(OpCodes.Ldc_I4, converterIndex);
il.Emit(OpCodes.Callvirt, fnListGetItem); // Converter
}
// "value = rdr.GetValue(i)"
il.Emit(OpCodes.Ldarg_0); // *,rdr
il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i
il.Emit(OpCodes.Callvirt, fnGetValue); // *,value
// Call the converter
if (converter != null)
il.Emit(OpCodes.Callvirt, fnInvoke);
// Assign it
il.Emit(OpCodes.Unbox_Any, pc.PropertyInfo.PropertyType); // poco,poco,value
il.Emit(OpCodes.Callvirt, pc.PropertyInfo.GetSetMethod()); // poco
}
il.MarkLabel(lblNext);
}
il.Emit(OpCodes.Ret);
// Cache it, return it
var del = (Func<IDataReader, T>)m.CreateDelegate(typeof(Func<IDataReader, T>));
PocoFactories.Add(key, del);
return del;
}
}
}
static Dictionary<Type, PocoData> m_PocoData = new Dictionary<Type, PocoData>();
static List<Func<object, object>> m_Converters = new List<Func<object, object>>();
static MethodInfo fnGetValue = typeof(IDataRecord).GetMethod("GetValue", new Type[] { typeof(int) });
static MethodInfo fnIsDBNull = typeof(IDataRecord).GetMethod("IsDBNull");
static FieldInfo fldConverters = typeof(PocoData).GetField("m_Converters", BindingFlags.Static | BindingFlags.GetField | BindingFlags.NonPublic);
static MethodInfo fnListGetItem = typeof(List<Func<object, object>>).GetProperty("Item").GetGetMethod();
static MethodInfo fnInvoke = typeof(Func<object, object>).GetMethod("Invoke");
public string TableName { get; private set; }
public string PrimaryKey { get; private set; }
public string QueryColumns { get; private set; }
public Dictionary<string, PocoColumn> Columns { get; private set; }
Dictionary<string, object> PocoFactories = new Dictionary<string, object>();
}
// ShareableConnection represents either a shared connection used by a transaction,
// or a one-off connection if not in a transaction.
// Non-shared connections are disposed
class ShareableConnection : IDisposable
{
public ShareableConnection(Database db)
{
_db = db;
_db.OpenSharedConnection();
}
public DbConnection Connection
{
get
{
return _db._sharedConnection;
}
}
Database _db;
public void Dispose()
{
_db.CloseSharedConnection();
}
}
// Member variables
string _connectionString;
string _providerName;
DbProviderFactory _factory;
DbConnection _sharedConnection;
DbTransaction _transaction;
int _sharedConnectionDepth;
int _transactionDepth;
bool _transactionCancelled;
string _lastSql;
object[] _lastArgs;
string _paramPrefix = "@";
}
// Transaction object helps maintain transaction depth counts
public class Transaction : IDisposable
{
public Transaction(Database db)
{
_db = db;
_db.BeginTransaction();
}
public void Complete()
{
_db.CompleteTransaction();
_db = null;
}
public void Dispose()
{
if (_db != null)
_db.AbortTransaction();
}
Database _db;
}
// Simple helper class for building SQL statments
public class Sql
{
public Sql()
{
}
public Sql(string sql, params object[] args)
{
_sql = sql;
_args = args;
}
string _sql;
object[] _args;
Sql _rhs;
string _sqlFinal;
object[] _argsFinal;
void Build()
{
// already built?
if (_sqlFinal != null)
return;
// Build it
var sb = new StringBuilder();
var args = new List<object>();
Build(sb, args, null);
_sqlFinal = sb.ToString();
_argsFinal = args.ToArray();
}
public string SQL
{
get
{
Build();
return _sqlFinal;
}
}
public object[] Arguments
{
get
{
Build();
return _argsFinal;
}
}
public Sql Append(Sql sql)
{
if (_rhs != null)
_rhs.Append(sql);
else
_rhs = sql;
return this;
}
public Sql Append(string sql, params object[] args)
{
return Append(new Sql(sql, args));
}
public Sql Where(string sql, params object[] args)
{
return Append(new Sql("WHERE " + sql, args));
}
public Sql OrderBy(params object[] args)
{
return Append(new Sql("ORDER BY " + String.Join(", ", (from x in args select x.ToString()).ToArray())));
}
public Sql Select(params object[] args)
{
return Append(new Sql("SELECT " + String.Join(", ", (from x in args select x.ToString()).ToArray())));
}
public Sql From(params object[] args)
{
return Append(new Sql("FROM " + String.Join(", ", (from x in args select x.ToString()).ToArray())));
}
static bool Is(Sql sql, string sqltype)
{
return sql != null && sql._sql != null && sql._sql.StartsWith(sqltype, StringComparison.InvariantCultureIgnoreCase);
}
public void Build(StringBuilder sb, List<object> args, Sql lhs)
{
if (!String.IsNullOrEmpty(_sql))
{
// Add SQL to the string
if (sb.Length > 0)
{
sb.Append("\n");
}
var sql = Database.ProcessParams(_sql, _args, args);
if (Is(lhs, "WHERE ") && Is(this, "WHERE "))
sql = "AND " + sql.Substring(6);
if (Is(lhs, "ORDER BY ") && Is(this, "ORDER BY "))
sql = ", " + sql.Substring(9);
sb.Append(sql);
}
// Now do rhs
if (_rhs != null)
_rhs.Build(sb, args, this);
}
}
}
......@@ -35,7 +35,11 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="SubSonic.Core">
<HintPath>SubSonic\SubSonic.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Data.Entity" />
<Reference Include="System.Data.Linq" />
......@@ -61,6 +65,7 @@
<Compile Include="Linq2Sql\Post.cs" />
<Compile Include="Massive\Massive.cs" />
<Compile Include="PerformanceTests.cs" />
<Compile Include="PetaPoco\PetaPoco.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Settings.Designer.cs">
......@@ -69,6 +74,26 @@
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
<Compile Include="SqlMapper.cs" />
<Compile Include="SubSonic\ActiveRecord.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>ActiveRecord.tt</DependentUpon>
</Compile>
<Compile Include="SubSonic\Context.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Context.tt</DependentUpon>
</Compile>
<Compile Include="SubSonic\StoredProcedures.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>StoredProcedures.tt</DependentUpon>
</Compile>
<Compile Include="SubSonic\Structs.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Structs.tt</DependentUpon>
</Compile>
<Compile Include="Tests.cs" />
</ItemGroup>
<ItemGroup>
......@@ -86,15 +111,35 @@
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<None Include="SubSonic\ActiveRecord.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>ActiveRecord.cs</LastGenOutput>
</None>
<None Include="SubSonic\Context.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Context.cs</LastGenOutput>
</None>
<None Include="SubSonic\Settings.ttinclude" />
<None Include="SubSonic\SQLServer.ttinclude" />
<None Include="SubSonic\StoredProcedures.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>StoredProcedures.cs</LastGenOutput>
</None>
<None Include="SubSonic\Structs.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Structs.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{3259AA49-8AA1-44D3-9025-A0B520596A8C}" />
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
</ItemGroup>
<ItemGroup>
<None Include="Linq2Sql\DataClasses.dbml.layout">
<DependentUpon>DataClasses.dbml</DependentUpon>
</None>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using SubSonic.DataProviders;
using SubSonic.Extensions;
using System.Linq.Expressions;
using SubSonic.Schema;
using System.Collections;
using SubSonic;
using SubSonic.Repository;
using System.ComponentModel;
using System.Data.Common;
namespace SubSonic
{
/// <summary>
/// A class which represents the Posts table in the tempdb Database.
/// </summary>
public partial class Post: IActiveRecord
{
#region Built-in testing
static TestRepository<Post> _testRepo;
static void SetTestRepo(){
_testRepo = _testRepo ?? new TestRepository<Post>(new SubSonic.tempdbDB());
}
public static void ResetTestRepo(){
_testRepo = null;
SetTestRepo();
}
public static void Setup(List<Post> testlist){
SetTestRepo();
foreach (var item in testlist)
{
_testRepo._items.Add(item);
}
}
public static void Setup(Post item) {
SetTestRepo();
_testRepo._items.Add(item);
}
public static void Setup(int testItems) {
SetTestRepo();
for(int i=0;i<testItems;i++){
Post item=new Post();
_testRepo._items.Add(item);
}
}
public bool TestMode = false;
#endregion
IRepository<Post> _repo;
ITable tbl;
bool _isNew;
public bool IsNew(){
return _isNew;
}
public void SetIsLoaded(bool isLoaded){
_isLoaded=isLoaded;
if(isLoaded)
OnLoaded();
}
public void SetIsNew(bool isNew){
_isNew=isNew;
}
bool _isLoaded;
public bool IsLoaded(){
return _isLoaded;
}
List<IColumn> _dirtyColumns;
public bool IsDirty(){
return _dirtyColumns.Count>0;
}
public List<IColumn> GetDirtyColumns (){
return _dirtyColumns;
}
SubSonic.tempdbDB _db;
public Post(string connectionString, string providerName) {
_db=new SubSonic.tempdbDB(connectionString, providerName);
Init();
}
void Init(){
TestMode=this._db.DataProvider.ConnectionString.Equals("test", StringComparison.InvariantCultureIgnoreCase);
_dirtyColumns=new List<IColumn>();
if(TestMode){
Post.SetTestRepo();
_repo=_testRepo;
}else{
_repo = new SubSonicRepository<Post>(_db);
}
tbl=_repo.GetTable();
SetIsNew(true);
OnCreated();
}
public Post(){
_db=new SubSonic.tempdbDB();
Init();
}
partial void OnCreated();
partial void OnLoaded();
partial void OnSaved();
partial void OnChanged();
public IList<IColumn> Columns{
get{
return tbl.Columns;
}
}
public Post(Expression<Func<Post, bool>> expression):this() {
SetIsLoaded(_repo.Load(this,expression));
}
internal static IRepository<Post> GetRepo(string connectionString, string providerName){
SubSonic.tempdbDB db;
if(String.IsNullOrEmpty(connectionString)){
db=new SubSonic.tempdbDB();
}else{
db=new SubSonic.tempdbDB(connectionString, providerName);
}
IRepository<Post> _repo;
if(db.TestMode){
Post.SetTestRepo();
_repo=_testRepo;
}else{
_repo = new SubSonicRepository<Post>(db);
}
return _repo;
}
internal static IRepository<Post> GetRepo(){
return GetRepo("","");
}
public static Post SingleOrDefault(Expression<Func<Post, bool>> expression) {
var repo = GetRepo();
var results=repo.Find(expression);
Post single=null;
if(results.Count() > 0){
single=results.ToList()[0];
single.OnLoaded();
single.SetIsLoaded(true);
single.SetIsNew(false);
}
return single;
}
public static Post SingleOrDefault(Expression<Func<Post, bool>> expression,string connectionString, string providerName) {
var repo = GetRepo(connectionString,providerName);
var results=repo.Find(expression);
Post single=null;
if(results.Count() > 0){
single=results.ToList()[0];
}
return single;
}
public static bool Exists(Expression<Func<Post, bool>> expression,string connectionString, string providerName) {
return All(connectionString,providerName).Any(expression);
}
public static bool Exists(Expression<Func<Post, bool>> expression) {
return All().Any(expression);
}
public static IList<Post> Find(Expression<Func<Post, bool>> expression) {
var repo = GetRepo();
return repo.Find(expression).ToList();
}
public static IList<Post> Find(Expression<Func<Post, bool>> expression,string connectionString, string providerName) {
var repo = GetRepo(connectionString,providerName);
return repo.Find(expression).ToList();
}
public static IQueryable<Post> All(string connectionString, string providerName) {
return GetRepo(connectionString,providerName).GetAll();
}
public static IQueryable<Post> All() {
return GetRepo().GetAll();
}
public static PagedList<Post> GetPaged(string sortBy, int pageIndex, int pageSize,string connectionString, string providerName) {
return GetRepo(connectionString,providerName).GetPaged(sortBy, pageIndex, pageSize);
}
public static PagedList<Post> GetPaged(string sortBy, int pageIndex, int pageSize) {
return GetRepo().GetPaged(sortBy, pageIndex, pageSize);
}
public static PagedList<Post> GetPaged(int pageIndex, int pageSize,string connectionString, string providerName) {
return GetRepo(connectionString,providerName).GetPaged(pageIndex, pageSize);
}
public static PagedList<Post> GetPaged(int pageIndex, int pageSize) {
return GetRepo().GetPaged(pageIndex, pageSize);
}
public string KeyName()
{
return "Id";
}
public object KeyValue()
{
return this.Id;
}
public void SetKeyValue(object value) {
if (value != null && value!=DBNull.Value) {
var settable = value.ChangeTypeTo<int>();
this.GetType().GetProperty(this.KeyName()).SetValue(this, settable, null);
}
}
public override string ToString(){
return this.Text.ToString();
}
public override bool Equals(object obj){
if(obj.GetType()==typeof(Post)){
Post compare=(Post)obj;
return compare.KeyValue()==this.KeyValue();
}else{
return base.Equals(obj);
}
}
public override int GetHashCode() {
return this.Id;
}
public string DescriptorValue()
{
return this.Text.ToString();
}
public string DescriptorColumn() {
return "Text";
}
public static string GetKeyColumn()
{
return "Id";
}
public static string GetDescriptorColumn()
{
return "Text";
}
#region ' Foreign Keys '
#endregion
int _Id;
public int Id
{
get { return _Id; }
set
{
if(_Id!=value){
_Id=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="Id");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
string _Text;
public string Text
{
get { return _Text; }
set
{
if(_Text!=value){
_Text=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="Text");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
DateTime _CreationDate;
public DateTime CreationDate
{
get { return _CreationDate; }
set
{
if(_CreationDate!=value){
_CreationDate=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="CreationDate");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
DateTime _LastChangeDate;
public DateTime LastChangeDate
{
get { return _LastChangeDate; }
set
{
if(_LastChangeDate!=value){
_LastChangeDate=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="LastChangeDate");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
int? _Counter1;
public int? Counter1
{
get { return _Counter1; }
set
{
if(_Counter1!=value){
_Counter1=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="Counter1");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
int? _Counter2;
public int? Counter2
{
get { return _Counter2; }
set
{
if(_Counter2!=value){
_Counter2=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="Counter2");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
int? _Counter3;
public int? Counter3
{
get { return _Counter3; }
set
{
if(_Counter3!=value){
_Counter3=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="Counter3");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
int? _Counter4;
public int? Counter4
{
get { return _Counter4; }
set
{
if(_Counter4!=value){
_Counter4=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="Counter4");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
int? _Counter5;
public int? Counter5
{
get { return _Counter5; }
set
{
if(_Counter5!=value){
_Counter5=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="Counter5");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
int? _Counter6;
public int? Counter6
{
get { return _Counter6; }
set
{
if(_Counter6!=value){
_Counter6=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="Counter6");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
int? _Counter7;
public int? Counter7
{
get { return _Counter7; }
set
{
if(_Counter7!=value){
_Counter7=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="Counter7");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
int? _Counter8;
public int? Counter8
{
get { return _Counter8; }
set
{
if(_Counter8!=value){
_Counter8=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="Counter8");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
int? _Counter9;
public int? Counter9
{
get { return _Counter9; }
set
{
if(_Counter9!=value){
_Counter9=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="Counter9");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
public DbCommand GetUpdateCommand() {
if(TestMode)
return _db.DataProvider.CreateCommand();
else
return this.ToUpdateQuery(_db.Provider).GetCommand().ToDbCommand();
}
public DbCommand GetInsertCommand() {
if(TestMode)
return _db.DataProvider.CreateCommand();
else
return this.ToInsertQuery(_db.Provider).GetCommand().ToDbCommand();
}
public DbCommand GetDeleteCommand() {
if(TestMode)
return _db.DataProvider.CreateCommand();
else
return this.ToDeleteQuery(_db.Provider).GetCommand().ToDbCommand();
}
public void Update(){
Update(_db.DataProvider);
}
public void Update(IDataProvider provider){
if(this._dirtyColumns.Count>0){
_repo.Update(this,provider);
_dirtyColumns.Clear();
}
OnSaved();
}
public void Add(){
Add(_db.DataProvider);
}
public void Add(IDataProvider provider){
var key=KeyValue();
if(key==null){
var newKey=_repo.Add(this,provider);
this.SetKeyValue(newKey);
}else{
_repo.Add(this,provider);
}
SetIsNew(false);
OnSaved();
}
public void Save() {
Save(_db.DataProvider);
}
public void Save(IDataProvider provider) {
if (_isNew) {
Add(provider);
} else {
Update(provider);
}
}
public void Delete(IDataProvider provider) {
_repo.Delete(KeyValue());
}
public void Delete() {
Delete(_db.DataProvider);
}
public static void Delete(Expression<Func<Post, bool>> expression) {
var repo = GetRepo();
repo.DeleteMany(expression);
}
public void Load(IDataReader rdr) {
Load(rdr, true);
}
public void Load(IDataReader rdr, bool closeReader) {
if (rdr.Read()) {
try {
rdr.Load(this);
SetIsNew(false);
SetIsLoaded(true);
} catch {
SetIsLoaded(false);
throw;
}
}else{
SetIsLoaded(false);
}
if (closeReader)
rdr.Dispose();
}
}
}
<#@ include file="SQLServer.ttinclude" #>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using SubSonic.DataProviders;
using SubSonic.Extensions;
using System.Linq.Expressions;
using SubSonic.Schema;
using System.Collections;
using SubSonic;
using SubSonic.Repository;
using System.ComponentModel;
using System.Data.Common;
namespace <#=Namespace #>
{
<#
var tables = LoadTables();
foreach(Table tbl in tables)
{
if(!ExcludeTables.Contains(tbl.Name))
{
#>
/// <summary>
/// A class which represents the <#=tbl.Name #> table in the <#=DatabaseName#> Database.
/// </summary>
public partial class <#=tbl.ClassName#>: IActiveRecord
{
#region Built-in testing
static TestRepository<<#=tbl.ClassName#>> _testRepo;
static void SetTestRepo(){
_testRepo = _testRepo ?? new TestRepository<<#=tbl.ClassName#>>(new <#=Namespace#>.<#=DatabaseName#>DB());
}
public static void ResetTestRepo(){
_testRepo = null;
SetTestRepo();
}
public static void Setup(List<<#=tbl.ClassName#>> testlist){
SetTestRepo();
foreach (var item in testlist)
{
_testRepo._items.Add(item);
}
}
public static void Setup(<#=tbl.ClassName#> item) {
SetTestRepo();
_testRepo._items.Add(item);
}
public static void Setup(int testItems) {
SetTestRepo();
for(int i=0;i<testItems;i++){
<#=tbl.ClassName#> item=new <#=tbl.ClassName#>();
_testRepo._items.Add(item);
}
}
public bool TestMode = false;
#endregion
IRepository<<#=tbl.ClassName#>> _repo;
ITable tbl;
bool _isNew;
public bool IsNew(){
return _isNew;
}
public void SetIsLoaded(bool isLoaded){
_isLoaded=isLoaded;
if(isLoaded)
OnLoaded();
}
public void SetIsNew(bool isNew){
_isNew=isNew;
}
bool _isLoaded;
public bool IsLoaded(){
return _isLoaded;
}
List<IColumn> _dirtyColumns;
public bool IsDirty(){
return _dirtyColumns.Count>0;
}
public List<IColumn> GetDirtyColumns (){
return _dirtyColumns;
}
<#=Namespace#>.<#=DatabaseName#>DB _db;
public <#=tbl.ClassName#>(string connectionString, string providerName) {
_db=new <#=Namespace#>.<#=DatabaseName#>DB(connectionString, providerName);
Init();
}
void Init(){
TestMode=this._db.DataProvider.ConnectionString.Equals("test", StringComparison.InvariantCultureIgnoreCase);
_dirtyColumns=new List<IColumn>();
if(TestMode){
<#=tbl.ClassName#>.SetTestRepo();
_repo=_testRepo;
}else{
_repo = new SubSonicRepository<<#=tbl.ClassName#>>(_db);
}
tbl=_repo.GetTable();
SetIsNew(true);
OnCreated();
}
public <#=tbl.ClassName#>(){
_db=new <#=Namespace#>.<#=DatabaseName#>DB();
Init();
}
partial void OnCreated();
partial void OnLoaded();
partial void OnSaved();
partial void OnChanged();
public IList<IColumn> Columns{
get{
return tbl.Columns;
}
}
public <#=tbl.ClassName#>(Expression<Func<<#=tbl.ClassName#>, bool>> expression):this() {
SetIsLoaded(_repo.Load(this,expression));
}
internal static IRepository<<#=tbl.ClassName#>> GetRepo(string connectionString, string providerName){
<#=Namespace#>.<#=DatabaseName#>DB db;
if(String.IsNullOrEmpty(connectionString)){
db=new <#=Namespace#>.<#=DatabaseName#>DB();
}else{
db=new <#=Namespace#>.<#=DatabaseName#>DB(connectionString, providerName);
}
IRepository<<#=tbl.ClassName#>> _repo;
if(db.TestMode){
<#=tbl.ClassName#>.SetTestRepo();
_repo=_testRepo;
}else{
_repo = new SubSonicRepository<<#=tbl.ClassName#>>(db);
}
return _repo;
}
internal static IRepository<<#=tbl.ClassName#>> GetRepo(){
return GetRepo("","");
}
public static <#=tbl.ClassName#> SingleOrDefault(Expression<Func<<#=tbl.ClassName#>, bool>> expression) {
var repo = GetRepo();
var results=repo.Find(expression);
<#=tbl.ClassName#> single=null;
if(results.Count() > 0){
single=results.ToList()[0];
single.OnLoaded();
single.SetIsLoaded(true);
single.SetIsNew(false);
}
return single;
}
public static <#=tbl.ClassName#> SingleOrDefault(Expression<Func<<#=tbl.ClassName#>, bool>> expression,string connectionString, string providerName) {
var repo = GetRepo(connectionString,providerName);
var results=repo.Find(expression);
<#=tbl.ClassName#> single=null;
if(results.Count() > 0){
single=results.ToList()[0];
}
return single;
}
public static bool Exists(Expression<Func<<#=tbl.ClassName#>, bool>> expression,string connectionString, string providerName) {
return All(connectionString,providerName).Any(expression);
}
public static bool Exists(Expression<Func<<#=tbl.ClassName#>, bool>> expression) {
return All().Any(expression);
}
public static IList<<#=tbl.ClassName#>> Find(Expression<Func<<#=tbl.ClassName#>, bool>> expression) {
var repo = GetRepo();
return repo.Find(expression).ToList();
}
public static IList<<#=tbl.ClassName#>> Find(Expression<Func<<#=tbl.ClassName#>, bool>> expression,string connectionString, string providerName) {
var repo = GetRepo(connectionString,providerName);
return repo.Find(expression).ToList();
}
public static IQueryable<<#=tbl.ClassName#>> All(string connectionString, string providerName) {
return GetRepo(connectionString,providerName).GetAll();
}
public static IQueryable<<#=tbl.ClassName#>> All() {
return GetRepo().GetAll();
}
public static PagedList<<#=tbl.ClassName#>> GetPaged(string sortBy, int pageIndex, int pageSize,string connectionString, string providerName) {
return GetRepo(connectionString,providerName).GetPaged(sortBy, pageIndex, pageSize);
}
public static PagedList<<#=tbl.ClassName#>> GetPaged(string sortBy, int pageIndex, int pageSize) {
return GetRepo().GetPaged(sortBy, pageIndex, pageSize);
}
public static PagedList<<#=tbl.ClassName#>> GetPaged(int pageIndex, int pageSize,string connectionString, string providerName) {
return GetRepo(connectionString,providerName).GetPaged(pageIndex, pageSize);
}
public static PagedList<<#=tbl.ClassName#>> GetPaged(int pageIndex, int pageSize) {
return GetRepo().GetPaged(pageIndex, pageSize);
}
public string KeyName()
{
return "<#=tbl.PK.CleanName #>";
}
public object KeyValue()
{
return this.<#=tbl.PK.CleanName#>;
}
public void SetKeyValue(object value) {
if (value != null && value!=DBNull.Value) {
var settable = value.ChangeTypeTo<<#=tbl.PK.SysType#>>();
this.GetType().GetProperty(this.KeyName()).SetValue(this, settable, null);
}
}
public override string ToString(){
<# if (tbl.ClassName == tbl.Descriptor.CleanName){ #>
return this.<#=tbl.Descriptor.CleanName+"X" #>.ToString();
<# } else { #>
return this.<#=tbl.Descriptor.CleanName #>.ToString();
<# } #>
}
public override bool Equals(object obj){
if(obj.GetType()==typeof(<#=tbl.ClassName#>)){
<#=tbl.ClassName#> compare=(<#=tbl.ClassName#>)obj;
return compare.KeyValue()==this.KeyValue();
}else{
return base.Equals(obj);
}
}
<# if(tbl.PK.SysType=="int"){#>
public override int GetHashCode() {
return this.<#=tbl.PK.CleanName #>;
}
<# }#>
public string DescriptorValue()
{
<# if (tbl.ClassName == tbl.Descriptor.CleanName){ #>
return this.<#=tbl.Descriptor.CleanName+"X" #>.ToString();
<# } else { #>
return this.<#=tbl.Descriptor.CleanName #>.ToString();
<# } #>
}
public string DescriptorColumn() {
return "<#=tbl.Descriptor.CleanName #>";
}
public static string GetKeyColumn()
{
return "<#=tbl.PK.CleanName #>";
}
public static string GetDescriptorColumn()
{
return "<#=tbl.Descriptor.CleanName #>";
}
#region ' Foreign Keys '
<#
List<string> fkCreated = new List<string>();
foreach(FKTable fk in tbl.FKTables)
{
if(!ExcludeTables.Contains(fk.OtherTable)){
string propName=fk.OtherQueryable;
if(fkCreated.Contains(propName))
{
propName=fk.OtherQueryable+fkCreated.Count.ToString();
}
fkCreated.Add(fk.OtherQueryable);
#>
public IQueryable<<#=fk.OtherClass #>> <#=propName #>
{
get
{
var repo=<#=Namespace #>.<#=fk.OtherClass#>.GetRepo();
return from items in repo.GetAll()
where items.<#=CleanUp(fk.OtherColumn)#> == _<#=CleanUp(fk.ThisColumn)#>
select items;
}
}
<#
}
}
#>
#endregion
<#
foreach(Column col in tbl.Columns)
{
if (tbl.ClassName == col.CleanName)
{
col.CleanName += "X";
}
#>
<#=col.SysType #><#=CheckNullable(col)#> _<#=col.CleanName #>;
public <#=col.SysType #><#=CheckNullable(col)#> <#=col.CleanName #>
{
get { return _<#=col.CleanName #>; }
set
{
if(_<#=col.CleanName #>!=value){
_<#=col.CleanName #>=value;
var col=tbl.Columns.SingleOrDefault(x=>x.Name=="<#=col.Name #>");
if(col!=null){
if(!_dirtyColumns.Any(x=>x.Name==col.Name) && _isLoaded){
_dirtyColumns.Add(col);
}
}
OnChanged();
}
}
}
<#
}
#>
public DbCommand GetUpdateCommand() {
<#if(tbl.Columns.Any(x=>x.Name.ToLower()=="modifiedon")){#>
if (!_dirtyColumns.Any(x => x.Name.ToLower() == "modifiedon")) {
this.<#=tbl.Columns.Single(x=>x.Name.ToLower()=="modifiedon").CleanName#>=<#=DatabaseName#>DB.DateTimeNowTruncatedDownToSecond();
}
<#}#>
if(TestMode)
return _db.DataProvider.CreateCommand();
else
return this.ToUpdateQuery(_db.Provider).GetCommand().ToDbCommand();
}
public DbCommand GetInsertCommand() {
if(TestMode)
return _db.DataProvider.CreateCommand();
else
return this.ToInsertQuery(_db.Provider).GetCommand().ToDbCommand();
}
public DbCommand GetDeleteCommand() {
if(TestMode)
return _db.DataProvider.CreateCommand();
else
return this.ToDeleteQuery(_db.Provider).GetCommand().ToDbCommand();
}
public void Update(){
Update(_db.DataProvider);
}
public void Update(IDataProvider provider){
<#if(tbl.Columns.Any(x=>x.Name=="ModifiedBy")){#>
if(String.IsNullOrEmpty(this.ModifiedBy))
this.ModifiedBy=Environment.UserName;
<#}#>
<#if(tbl.Columns.Any(x=>x.Name=="ModifiedOn")){#>
this.ModifiedOn=<#=DatabaseName#>DB.DateTimeNowTruncatedDownToSecond();
<#}#>
if(this._dirtyColumns.Count>0){
_repo.Update(this,provider);
_dirtyColumns.Clear();
}
OnSaved();
}
public void Add(){
Add(_db.DataProvider);
}
<#if(tbl.Columns.Any(x=>x.Name=="ModifiedBy")){#>
public void Update(string username){
this.ModifiedBy=username;
Update();
}
public void Update(string username, IDataProvider provider){
this.ModifiedBy=username;
Update(provider);
}
<#}#>
public void Add(IDataProvider provider){
<#if(tbl.Columns.Any(x=>x.Name=="CreatedOn")){#>
this.CreatedOn=<#=DatabaseName#>DB.DateTimeNowTruncatedDownToSecond();
<#}#>
<#if(tbl.Columns.Any(x=>x.Name=="CreatedBy")){#>
if(String.IsNullOrEmpty(this.CreatedBy))
this.CreatedBy=Environment.UserName;
<#}#>
<#if(tbl.Columns.Any(x=>x.Name=="ModifiedOn")){#>
this.ModifiedOn=<#=DatabaseName#>DB.DateTimeNowTruncatedDownToSecond();
<#}#>
<#if(tbl.Columns.Any(x=>x.Name=="ModifiedBy")){#>
if(String.IsNullOrEmpty(this.ModifiedBy))
this.ModifiedBy=Environment.UserName;
<#}#>
var key=KeyValue();
if(key==null){
var newKey=_repo.Add(this,provider);
this.SetKeyValue(newKey);
}else{
_repo.Add(this,provider);
}
SetIsNew(false);
OnSaved();
}
<#if(tbl.Columns.Any(x=>x.Name=="CreatedBy")){#>
public void Add(string username){
this.CreatedBy=username;
Add();
}
public void Add(string username, IDataProvider provider){
this.CreatedBy=username;
Add(provider);
}
<#}#>
public void Save() {
Save(_db.DataProvider);
}
public void Save(IDataProvider provider) {
if (_isNew) {
Add(provider);
} else {
Update(provider);
}
}
<#if(tbl.Columns.Any(x=>x.Name=="CreatedBy" || x.Name=="ModifiedBy")){#>
public void Save(string username, IDataProvider provider) {
if (_isNew) {
<#if(tbl.Columns.Any(x=>x.Name=="CreatedBy")){#>
Add(username,provider);
<#}else{#>
Add(provider);
<#}#>
} else {
<#if(tbl.Columns.Any(x=>x.Name=="ModifiedBy")){#>
Update(username,provider);
<#}else{#>
Update(provider);
<#}#>
}
}
<#}#>
public void Delete(IDataProvider provider) {
<#if(tbl.HasLogicalDelete()){#>
this.<#=tbl.DeleteColumn.CleanName#>=true;
_repo.Update(this,provider);
<#}else{#>
_repo.Delete(KeyValue());
<#}#>
}
public void Delete() {
Delete(_db.DataProvider);
}
public static void Delete(Expression<Func<<#=tbl.ClassName#>, bool>> expression) {
var repo = GetRepo();
<#if(tbl.HasLogicalDelete()){#>
List<<#=tbl.ClassName#>> items=repo.GetAll().Where(expression).ToList();
items.ForEach(x=>x.<#=tbl.DeleteColumn.CleanName#>=true);
repo.Update(items);
<#}else{#>
repo.DeleteMany(expression);
<#}#>
}
<#if(tbl.HasLogicalDelete()){#>
public static void Destroy(Func<<#=tbl.ClassName#>, bool> expression) {
var repo = GetRepo();
repo.Delete(expression);
}
public static void Destroy(object key) {
var repo = GetRepo();
repo.Delete(key);
}
public static void Destroy(object key, IDataProvider provider) {
var repo = GetRepo();
repo.Delete(key,provider);
}
public void Destroy() {
_repo.Delete(KeyValue());
}
public void Destroy(IDataProvider provider) {
_repo.Delete(KeyValue(), provider);
}
<#}#>
public void Load(IDataReader rdr) {
Load(rdr, true);
}
public void Load(IDataReader rdr, bool closeReader) {
if (rdr.Read()) {
try {
rdr.Load(this);
SetIsNew(false);
SetIsLoaded(true);
} catch {
SetIsLoaded(false);
throw;
}
}else{
SetIsLoaded(false);
}
if (closeReader)
rdr.Dispose();
}
}
<# }
}
#>
}
using System;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using SubSonic.DataProviders;
using SubSonic.Extensions;
using SubSonic.Linq.Structure;
using SubSonic.Query;
using SubSonic.Schema;
using System.Data.Common;
using System.Collections.Generic;
namespace SubSonic
{
public partial class tempdbDB : IQuerySurface
{
public IDataProvider DataProvider;
public DbQueryProvider provider;
public static IDataProvider DefaultDataProvider { get; set; }
public bool TestMode
{
get
{
return DataProvider.ConnectionString.Equals("test", StringComparison.InvariantCultureIgnoreCase);
}
}
public tempdbDB()
{
if (DefaultDataProvider == null) {
DataProvider = ProviderFactory.GetProvider("Smackdown.Properties.Settings.tempdbConnectionString");
}
else {
DataProvider = DefaultDataProvider;
}
Init();
}
public tempdbDB(string connectionStringName)
{
DataProvider = ProviderFactory.GetProvider(connectionStringName);
Init();
}
public tempdbDB(string connectionString, string providerName)
{
DataProvider = ProviderFactory.GetProvider(connectionString,providerName);
Init();
}
public ITable FindByPrimaryKey(string pkName)
{
return DataProvider.Schema.Tables.SingleOrDefault(x => x.PrimaryKey.Name.Equals(pkName, StringComparison.InvariantCultureIgnoreCase));
}
public Query<T> GetQuery<T>()
{
return new Query<T>(provider);
}
public ITable FindTable(string tableName)
{
return DataProvider.FindTable(tableName);
}
public IDataProvider Provider
{
get { return DataProvider; }
set {DataProvider=value;}
}
public DbQueryProvider QueryProvider
{
get { return provider; }
}
BatchQuery _batch = null;
public void Queue<T>(IQueryable<T> qry)
{
if (_batch == null)
_batch = new BatchQuery(Provider, QueryProvider);
_batch.Queue(qry);
}
public void Queue(ISqlQuery qry)
{
if (_batch == null)
_batch = new BatchQuery(Provider, QueryProvider);
_batch.Queue(qry);
}
public void ExecuteTransaction(IList<DbCommand> commands)
{
if(!TestMode)
{
using(var connection = commands[0].Connection)
{
if (connection.State == ConnectionState.Closed)
connection.Open();
using (var trans = connection.BeginTransaction())
{
foreach (var cmd in commands)
{
cmd.Transaction = trans;
cmd.Connection = connection;
cmd.ExecuteNonQuery();
}
trans.Commit();
}
connection.Close();
}
}
}
public IDataReader ExecuteBatch()
{
if (_batch == null)
throw new InvalidOperationException("There's nothing in the queue");
if(!TestMode)
return _batch.ExecuteReader();
return null;
}
public Query<Post> Posts { get; set; }
#region ' Aggregates and SubSonic Queries '
public Select SelectColumns(params string[] columns)
{
return new Select(DataProvider, columns);
}
public Select Select
{
get { return new Select(this.Provider); }
}
public Insert Insert
{
get { return new Insert(this.Provider); }
}
public Update<T> Update<T>() where T:new()
{
return new Update<T>(this.Provider);
}
public SqlQuery Delete<T>(Expression<Func<T,bool>> column) where T:new()
{
LambdaExpression lamda = column;
SqlQuery result = new Delete<T>(this.Provider);
result = result.From<T>();
result.Constraints=lamda.ParseConstraints().ToList();
return result;
}
public SqlQuery Max<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = DataProvider.FindTable(objectName).Name;
return new Select(DataProvider, new Aggregate(colName, AggregateFunction.Max)).From(tableName);
}
public SqlQuery Min<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Min)).From(tableName);
}
public SqlQuery Sum<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Sum)).From(tableName);
}
public SqlQuery Avg<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Avg)).From(tableName);
}
public SqlQuery Count<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Count)).From(tableName);
}
public SqlQuery Variance<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Var)).From(tableName);
}
public SqlQuery StandardDeviation<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.StDev)).From(tableName);
}
#endregion
void Init()
{
provider = new DbQueryProvider(this.Provider);
#region ' Query Defs '
Posts = new Query<Post>(provider);
#endregion
#region ' Schemas '
if(DataProvider.Schema.Tables.Count == 0)
{
DataProvider.Schema.Tables.Add(new PostsTable(DataProvider));
}
#endregion
}
#region ' Helpers '
internal static DateTime DateTimeNowTruncatedDownToSecond() {
var now = DateTime.Now;
return now.AddTicks(-now.Ticks % TimeSpan.TicksPerSecond);
}
#endregion
}
}
\ No newline at end of file
<#@ template language="C#v3.5" debug="False" hostspecific="True" #>
<#@ output extension=".cs" #>
<#@ include file="SQLServer.ttinclude" #>
<#
var tables = LoadTables();
#>
using System;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using SubSonic.DataProviders;
using SubSonic.Extensions;
using SubSonic.Linq.Structure;
using SubSonic.Query;
using SubSonic.Schema;
using System.Data.Common;
using System.Collections.Generic;
namespace <#=Namespace#>
{
public partial class <#=DatabaseName#>DB : IQuerySurface
{
public IDataProvider DataProvider;
public DbQueryProvider provider;
public static IDataProvider DefaultDataProvider { get; set; }
public bool TestMode
{
get
{
return DataProvider.ConnectionString.Equals("test", StringComparison.InvariantCultureIgnoreCase);
}
}
public <#=DatabaseName#>DB()
{
if (DefaultDataProvider == null) {
DataProvider = ProviderFactory.GetProvider("<#=ConnectionStringName#>");
}
else {
DataProvider = DefaultDataProvider;
}
Init();
}
public <#=DatabaseName#>DB(string connectionStringName)
{
DataProvider = ProviderFactory.GetProvider(connectionStringName);
Init();
}
public <#=DatabaseName#>DB(string connectionString, string providerName)
{
DataProvider = ProviderFactory.GetProvider(connectionString,providerName);
Init();
}
public ITable FindByPrimaryKey(string pkName)
{
return DataProvider.Schema.Tables.SingleOrDefault(x => x.PrimaryKey.Name.Equals(pkName, StringComparison.InvariantCultureIgnoreCase));
}
public Query<T> GetQuery<T>()
{
return new Query<T>(provider);
}
public ITable FindTable(string tableName)
{
return DataProvider.FindTable(tableName);
}
public IDataProvider Provider
{
get { return DataProvider; }
set {DataProvider=value;}
}
public DbQueryProvider QueryProvider
{
get { return provider; }
}
BatchQuery _batch = null;
public void Queue<T>(IQueryable<T> qry)
{
if (_batch == null)
_batch = new BatchQuery(Provider, QueryProvider);
_batch.Queue(qry);
}
public void Queue(ISqlQuery qry)
{
if (_batch == null)
_batch = new BatchQuery(Provider, QueryProvider);
_batch.Queue(qry);
}
public void ExecuteTransaction(IList<DbCommand> commands)
{
if(!TestMode)
{
using(var connection = commands[0].Connection)
{
if (connection.State == ConnectionState.Closed)
connection.Open();
using (var trans = connection.BeginTransaction())
{
foreach (var cmd in commands)
{
cmd.Transaction = trans;
cmd.Connection = connection;
cmd.ExecuteNonQuery();
}
trans.Commit();
}
connection.Close();
}
}
}
public IDataReader ExecuteBatch()
{
if (_batch == null)
throw new InvalidOperationException("There's nothing in the queue");
if(!TestMode)
return _batch.ExecuteReader();
return null;
}
<# //################################################ IQueryable ####################################### #>
<# foreach(Table tbl in tables){
if(!ExcludeTables.Contains(tbl.Name))
{
#>
public Query<<#=tbl.ClassName#>> <#=tbl.QueryableName#> { get; set; }
<#
}
}
#>
<# //################################################ Aggregates and Queries ####################################### #>
#region ' Aggregates and SubSonic Queries '
public Select SelectColumns(params string[] columns)
{
return new Select(DataProvider, columns);
}
public Select Select
{
get { return new Select(this.Provider); }
}
public Insert Insert
{
get { return new Insert(this.Provider); }
}
public Update<T> Update<T>() where T:new()
{
return new Update<T>(this.Provider);
}
public SqlQuery Delete<T>(Expression<Func<T,bool>> column) where T:new()
{
LambdaExpression lamda = column;
SqlQuery result = new Delete<T>(this.Provider);
result = result.From<T>();
result.Constraints=lamda.ParseConstraints().ToList();
return result;
}
public SqlQuery Max<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = DataProvider.FindTable(objectName).Name;
return new Select(DataProvider, new Aggregate(colName, AggregateFunction.Max)).From(tableName);
}
public SqlQuery Min<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Min)).From(tableName);
}
public SqlQuery Sum<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Sum)).From(tableName);
}
public SqlQuery Avg<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Avg)).From(tableName);
}
public SqlQuery Count<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Count)).From(tableName);
}
public SqlQuery Variance<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Var)).From(tableName);
}
public SqlQuery StandardDeviation<T>(Expression<Func<T,object>> column)
{
LambdaExpression lamda = column;
string colName = lamda.ParseObjectValue();
string objectName = typeof(T).Name;
string tableName = this.Provider.FindTable(objectName).Name;
return new Select(this.Provider, new Aggregate(colName, AggregateFunction.StDev)).From(tableName);
}
#endregion
void Init()
{
provider = new DbQueryProvider(this.Provider);
<#
//################################################ QUERIES ####################################### #>
#region ' Query Defs '
<#
foreach(Table tbl in tables)
{
if(!ExcludeTables.Contains(tbl.Name))
{
#>
<#=tbl.QueryableName#> = new Query<<#=tbl.ClassName#>>(provider);
<#
}
#>
<#
}
#>
#endregion
<#//################################################ SCHEMAS ####################################### #>
#region ' Schemas '
if(DataProvider.Schema.Tables.Count == 0)
{
<#
foreach(Table tbl in tables)
{
if(!ExcludeTables.Contains(tbl.Name))
{
#>
DataProvider.Schema.Tables.Add(new <#=tbl.CleanName#>Table(DataProvider));
<#
}
}
#>
}
#endregion
}
<#//################################################ HELPERS ####################################### #>
#region ' Helpers '
internal static DateTime DateTimeNowTruncatedDownToSecond() {
var now = DateTime.Now;
return now.AddTicks(-now.Ticks % TimeSpan.TicksPerSecond);
}
#endregion
}
}
\ No newline at end of file
<#@ include file="Settings.ttinclude" #>
<#+
IDataReader GetReader(string sql){
SqlConnection conn=new SqlConnection(ConnectionString);
SqlCommand cmd=new SqlCommand(sql,conn);
conn.Open();
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
SqlCommand GetCommand(string sql){
SqlConnection conn=new SqlConnection(ConnectionString);
SqlCommand cmd=new SqlCommand(sql,conn);
conn.Open();
return cmd;
}
const string FKSql=@"SELECT
ThisTable = FK.TABLE_NAME,
ThisColumn = CU.COLUMN_NAME,
OtherTable = PK.TABLE_NAME,
OtherColumn = PT.COLUMN_NAME,
Constraint_Name = C.CONSTRAINT_NAME,
Owner = FK.TABLE_SCHEMA
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN
(
SELECT i1.TABLE_NAME, i2.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
)
PT ON PT.TABLE_NAME = PK.TABLE_NAME
WHERE FK.Table_NAME=@tableName OR PK.Table_NAME=@tableName";
const string TABLE_SQL=@"SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE'";
const string COLUMN_SQL=@"SELECT
TABLE_CATALOG AS [Database],
TABLE_SCHEMA AS Owner,
TABLE_NAME AS TableName,
COLUMN_NAME AS ColumnName,
ORDINAL_POSITION AS OrdinalPosition,
COLUMN_DEFAULT AS DefaultSetting,
IS_NULLABLE AS IsNullable, DATA_TYPE AS DataType,
CHARACTER_MAXIMUM_LENGTH AS MaxLength,
DATETIME_PRECISION AS DatePrecision,
COLUMNPROPERTY(object_id('[' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']'), COLUMN_NAME, 'IsIdentity') AS IsIdentity,
COLUMNPROPERTY(object_id('[' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']'), COLUMN_NAME, 'IsComputed') as IsComputed
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME=@tableName
ORDER BY OrdinalPosition ASC";
List<SPParam> GetSPParams(string spName){
var result=new List<SPParam>();
string dbName = null;
if(!String.IsNullOrEmpty(DatabaseName))
dbName = DatabaseName;
string[] restrictions = new string[4] { dbName , null, spName, null };
using(SqlConnection conn=new SqlConnection(ConnectionString)){
conn.Open();
var sprocs=conn.GetSchema("ProcedureParameters", restrictions);
conn.Close();
foreach(DataRow row in sprocs.Select("", "ORDINAL_POSITION")){
SPParam p=new SPParam();
p.SysType=GetSysType(row["DATA_TYPE"].ToString());
p.DbType=GetDbType(row["DATA_TYPE"].ToString()).ToString();
p.Name=row["PARAMETER_NAME"].ToString().Replace("@","");
p.CleanName=CleanUp(p.Name);
result.Add(p);
}
}
return result;
}
List<SP> GetSPs(){
var result=new List<SP>();
//pull the SPs
DataTable sprocs=null;
DataTable parameters=null;
using(SqlConnection conn=new SqlConnection(ConnectionString)){
conn.Open();
sprocs=conn.GetSchema("Procedures");
conn.Close();
}
foreach(DataRow row in sprocs.Rows){
string spType=row["ROUTINE_TYPE"].ToString();
var sp=new SP();
sp.Name=row["ROUTINE_NAME"].ToString();
if(spType=="PROCEDURE" &! sp.Name.StartsWith("sp_")){
sp.CleanName=CleanUp(sp.Name);
sp.Parameters=GetSPParams(sp.Name);
result.Add(sp);
}
}
return result;
}
List<Table> LoadTables(){
var result=new List<Table>();
//pull the tables in a reader
using(IDataReader rdr=GetReader(TABLE_SQL)){
while(rdr.Read()){
Table tbl=new Table();
tbl.Name=rdr["TABLE_NAME"].ToString();
tbl.Schema=rdr["TABLE_SCHEMA"].ToString();
tbl.Columns=LoadColumns(tbl);
tbl.PrimaryKey=GetPK(tbl.Name);
tbl.CleanName=CleanUp(tbl.Name);
tbl.ClassName=Inflector.MakeSingular(tbl.CleanName);
tbl.QueryableName=Inflector.MakePlural(tbl.ClassName);
//set the PK for the columns
var pkColumn=tbl.Columns.SingleOrDefault(x=>x.Name.ToLower().Trim()==tbl.PrimaryKey.ToLower().Trim());
if(pkColumn!=null)
pkColumn.IsPK=true;
tbl.FKTables=LoadFKTables(tbl.Name);
result.Add(tbl);
}
}
foreach(Table tbl in result){
//loop the FK tables and see if there's a match for our FK columns
foreach(Column col in tbl.Columns){
col.IsForeignKey=tbl.FKTables.Any(
x=>x.ThisColumn.Equals(col.Name,StringComparison.InvariantCultureIgnoreCase)
);
}
}
return result;
}
List<Column> LoadColumns(Table tbl){
var result=new List<Column>();
var cmd=GetCommand(COLUMN_SQL);
cmd.Parameters.AddWithValue("@tableName",tbl.Name);
using(IDataReader rdr=cmd.ExecuteReader(CommandBehavior.CloseConnection)){
while(rdr.Read()){
Column col=new Column();
col.Name=rdr["ColumnName"].ToString();
col.CleanName=CleanUp(col.Name);
col.DataType=rdr["DataType"].ToString();
col.SysType=GetSysType(col.DataType);
col.DbType=GetDbType(col.DataType);
col.AutoIncrement=rdr["IsIdentity"].ToString()=="1";
col.IsNullable=rdr["IsNullable"].ToString()=="YES";
int.TryParse(rdr["MaxLength"].ToString(),out col.MaxLength);
result.Add(col);
}
}
return result;
}
List<FKTable> LoadFKTables(string tableName){
//this is a "bi-directional" scheme
//which pulls both 1-many and many-1
var result=new List<FKTable>();
var cmd=GetCommand(FKSql);
cmd.Parameters.AddWithValue("@tableName",tableName);
using(IDataReader rdr=cmd.ExecuteReader(CommandBehavior.CloseConnection)){
while(rdr.Read()){
FKTable fk=new FKTable();
string thisTable=rdr["ThisTable"].ToString();
if(tableName.ToLower()==thisTable.ToLower()){
fk.ThisTable=rdr["ThisTable"].ToString();
fk.ThisColumn=rdr["ThisColumn"].ToString();
fk.OtherTable=rdr["OtherTable"].ToString();
fk.OtherColumn=rdr["OtherColumn"].ToString();
}else{
fk.ThisTable=rdr["OtherTable"].ToString();
fk.ThisColumn=rdr["OtherColumn"].ToString();
fk.OtherTable=rdr["ThisTable"].ToString();
fk.OtherColumn=rdr["ThisColumn"].ToString();
}
fk.OtherClass=Inflector.MakeSingular(CleanUp(fk.OtherTable));
fk.OtherQueryable=Inflector.MakePlural(fk.OtherClass);
result.Add(fk);
}
}
return result;
}
string GetPK(string table){
string pk="";
DataTable pkTable=new DataTable();
string sql=@"SELECT KCU.COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU
JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
ON KCU.CONSTRAINT_NAME=TC.CONSTRAINT_NAME
WHERE TC.CONSTRAINT_TYPE='PRIMARY KEY'
AND KCU.TABLE_NAME=@tableName";
var cmd=GetCommand(sql);
cmd.Parameters.AddWithValue("@tableName",table);
var result=cmd.ExecuteScalar();
cmd.Dispose();
if(result!=null)
pk=result.ToString();
return pk;
}
string GetSysType(string sqlType){
string sysType="string";
switch (sqlType) {
case "bigint":
sysType = "long";
break;
case "smallint":
sysType= "short";
break;
case "int":
sysType= "int";
break;
case "uniqueidentifier":
sysType= "Guid";
break;
case "smalldatetime":
case "datetime":
case "date":
sysType= "DateTime";
break;
case "float":
sysType="double";
break;
case "real":
case "numeric":
case "smallmoney":
case "decimal":
case "money":
sysType= "decimal";
break;
case "tinyint":
sysType = "byte";
break;
case "bit":
sysType= "bool";
break;
case "image":
case "binary":
case "varbinary":
case "timestamp":
sysType= "byte[]";
break;
}
return sysType;
}
DbType GetDbType(string sqlType){
switch(sqlType)
{
case "varchar":
return DbType.AnsiString;
case "nvarchar":
return DbType.String;
case "int":
return DbType.Int32;
case "uniqueidentifier":
return DbType.Guid;
case "datetime":
return DbType.DateTime;
case "bigint":
return DbType.Int64;
case "binary":
return DbType.Binary;
case "bit":
return DbType.Boolean;
case "char":
return DbType.AnsiStringFixedLength;
case "decimal":
return DbType.Decimal;
case "float":
return DbType.Double;
case "image":
return DbType.Binary;
case "money":
return DbType.Currency;
case "nchar":
return DbType.String;
case "ntext":
return DbType.String;
case "numeric":
return DbType.Decimal;
case "real":
return DbType.Single;
case "smalldatetime":
return DbType.DateTime;
case "smallint":
return DbType.Int16;
case "smallmoney":
return DbType.Currency;
case "sql_variant":
return DbType.String;
case "sysname":
return DbType.String;
case "text":
return DbType.AnsiString;
case "timestamp":
return DbType.Binary;
case "tinyint":
return DbType.Byte;
case "varbinary":
return DbType.Binary;
case "xml":
return DbType.Xml;
default:
return DbType.AnsiString;
}
}
#>
\ No newline at end of file
<#@ template language="C#v3.5" debug="True" hostspecific="True" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Configuration" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Data.Common" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Configuration" #>
<#+
const string Namespace = "SubSonic";
const string ConnectionStringName = "Smackdown.Properties.Settings.tempdbConnectionString";
//This is the name of your database and is used in naming
//the repository. By default we set it to the connection string name
const string DatabaseName = "tempdb";
const bool TreatTinyint1AsBool = false;
//this is a list of tables you don't want generated
string[] ExcludeTables = new string[]{
"sysdiagrams",
"BuildVersion",
};
string CleanUp(string tableName){
string result=tableName;
//strip blanks
result=result.Replace(" ","");
//put your logic here...
return result;
}
string CheckNullable(Column col){
string result="";
if(col.IsNullable && col.SysType !="byte[]" && col.SysType !="string")
result="?";
return result;
}
string GetConnectionString(string connectionStringName){
var _CurrentProject = GetCurrentProject();
string result="";
ExeConfigurationFileMap configFile = new ExeConfigurationFileMap();
configFile.ExeConfigFilename = GetConfigPath();
if (string.IsNullOrEmpty(configFile.ExeConfigFilename))
throw new ArgumentNullException("The project does not contain App.config or Web.config file.");
var config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);
var connSection=config.ConnectionStrings;
//if the connectionString is empty - which is the defauls
//look for count-1 - this is the last connection string
//and takes into account AppServices and LocalSqlServer
if(string.IsNullOrEmpty(connectionStringName)){
if(connSection.ConnectionStrings.Count>1){
result=connSection.ConnectionStrings[connSection.ConnectionStrings.Count-1].ConnectionString;
}
}else{
try{
result=connSection.ConnectionStrings[connectionStringName].ConnectionString;
}catch{
result="There is no connection string name called '"+connectionStringName+"'";
}
}
return result;
}
string _connectionString="";
public string ConnectionString{
get {
if(String.IsNullOrEmpty(_connectionString)){
_connectionString=GetConnectionString(ConnectionStringName);
}
if(_connectionString.Contains("|DataDirectory|")){
//have to replace it
string dataFilePath=GetDataDirectory();
_connectionString=_connectionString.Replace("|DataDirectory|",dataFilePath);
}
return _connectionString;
}
}
public EnvDTE.Project GetCurrentProject() {
IServiceProvider _ServiceProvider = (IServiceProvider)Host;
if (_ServiceProvider == null)
throw new Exception("Host property returned unexpected value (null)");
EnvDTE.DTE dte = (EnvDTE.DTE)_ServiceProvider.GetService(typeof(EnvDTE.DTE));
if (dte == null)
throw new Exception("Unable to retrieve EnvDTE.DTE");
Array activeSolutionProjects = (Array)dte.ActiveSolutionProjects;
if (activeSolutionProjects == null)
throw new Exception("DTE.ActiveSolutionProjects returned null");
EnvDTE.Project dteProject = (EnvDTE.Project)activeSolutionProjects.GetValue(0);
if (dteProject == null)
throw new Exception("DTE.ActiveSolutionProjects[0] returned null");
return dteProject;
}
private string GetProjectPath()
{
EnvDTE.Project project = GetCurrentProject();
System.IO.FileInfo info = new System.IO.FileInfo(project.FullName);
return info.Directory.FullName;
}
private string GetConfigPath()
{
EnvDTE.Project project = GetCurrentProject();
foreach (EnvDTE.ProjectItem item in project.ProjectItems)
{
// if it is the app.config file, then open it up
if (item.Name.Equals("App.config",StringComparison.InvariantCultureIgnoreCase) || item.Name.Equals("Web.config",StringComparison.InvariantCultureIgnoreCase))
return GetProjectPath() + "\\" + item.Name;
}
return String.Empty;
}
public string GetDataDirectory(){
EnvDTE.Project project=GetCurrentProject();
return System.IO.Path.GetDirectoryName(project.FileName)+"\\App_Data\\";
}
public class Table{
public List<Column> Columns;
public List<FKTable> FKTables;
public string Name;
public string CleanName;
public string ClassName;
public string PrimaryKey;
public string Schema;
public string QueryableName;
public bool HasLogicalDelete(){
return this.Columns.Any(x=>x.Name.ToLower()=="deleted" || x.Name.ToLower()=="isdeleted");
}
public Column DeleteColumn{
get{
Column result=null;
if(this.Columns.Any(x=>x.Name.ToLower()=="deleted"))
result=this.Columns.Single(x=>x.Name.ToLower()=="deleted");
if(this.Columns.Any(x=>x.Name.ToLower()=="isdeleted"))
result=this.Columns.Single(x=>x.Name.ToLower()=="isdeleted");
return result;
}
}
public Column PK{
get{
return this.Columns.FirstOrDefault(x=>x.IsPK) ?? this.Columns[0];
}
}
public Column Descriptor{
get{
if(this.Columns.Count==1){
return this.Columns[0];
}else{
//get the first string column
Column result=null;
result=this.Columns.FirstOrDefault(x=>x.SysType.ToLower().Trim()=="string");
if(result==null)
result=this.Columns[1];
return result;
}
}
}
}
public class Column{
public string Name;
public string CleanName;
public string SysType;
public string DataType;
public DbType DbType;
public bool AutoIncrement;
public bool IsPK;
public int MaxLength;
public bool IsNullable;
public bool IsForeignKey;
public bool IsUnsigned;
}
public class FKTable{
public string ThisTable;
public string ThisColumn;
public string OtherTable;
public string OtherColumn;
public string OtherClass;
public string OtherQueryable;
}
public class SP{
public string Name;
public string CleanName;
public string ClassName;
public List<SPParam> Parameters;
public SP(){
Parameters=new List<SPParam>();
}
public string ArgList{
get{
StringBuilder sb=new StringBuilder();
int loopCount=1;
foreach(var par in Parameters){
sb.AppendFormat("{0} {1}", par.SysType,par.CleanName);
if(loopCount<Parameters.Count)
sb.Append(",");
loopCount++;
}
return sb.ToString();
}
}
}
public class SPParam{
public string Name;
public string CleanName;
public string SysType;
public string DbType;
}
/*
* SubSonic - http://subsonicproject.com
*
* The contents of this file are subject to the New BSD
* License (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.opensource.org/licenses/bsd-license.php
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*/
/// <summary>
/// Summary for the Inflector class
/// </summary>
public static class Inflector {
private static readonly List<InflectorRule> _plurals = new List<InflectorRule>();
private static readonly List<InflectorRule> _singulars = new List<InflectorRule>();
private static readonly List<string> _uncountables = new List<string>();
/// <summary>
/// Initializes the <see cref="Inflector"/> class.
/// </summary>
static Inflector() {
AddPluralRule("$", "s");
AddPluralRule("s$", "s");
AddPluralRule("(ax|test)is$", "$1es");
AddPluralRule("(octop|vir)us$", "$1i");
AddPluralRule("(alias|status)$", "$1es");
AddPluralRule("(bu)s$", "$1ses");
AddPluralRule("(buffal|tomat)o$", "$1oes");
AddPluralRule("([ti])um$", "$1a");
AddPluralRule("sis$", "ses");
AddPluralRule("(?:([^f])fe|([lr])f)$", "$1$2ves");
AddPluralRule("(hive)$", "$1s");
AddPluralRule("([^aeiouy]|qu)y$", "$1ies");
AddPluralRule("(x|ch|ss|sh)$", "$1es");
AddPluralRule("(matr|vert|ind)ix|ex$", "$1ices");
AddPluralRule("([m|l])ouse$", "$1ice");
AddPluralRule("^(ox)$", "$1en");
AddPluralRule("(quiz)$", "$1zes");
AddSingularRule("s$", String.Empty);
AddSingularRule("ss$", "ss");
AddSingularRule("(n)ews$", "$1ews");
AddSingularRule("([ti])a$", "$1um");
AddSingularRule("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis");
AddSingularRule("(^analy)ses$", "$1sis");
AddSingularRule("([^f])ves$", "$1fe");
AddSingularRule("(hive)s$", "$1");
AddSingularRule("(tive)s$", "$1");
AddSingularRule("([lr])ves$", "$1f");
AddSingularRule("([^aeiouy]|qu)ies$", "$1y");
AddSingularRule("(s)eries$", "$1eries");
AddSingularRule("(m)ovies$", "$1ovie");
AddSingularRule("(x|ch|ss|sh)es$", "$1");
AddSingularRule("([m|l])ice$", "$1ouse");
AddSingularRule("(bus)es$", "$1");
AddSingularRule("(o)es$", "$1");
AddSingularRule("(shoe)s$", "$1");
AddSingularRule("(cris|ax|test)es$", "$1is");
AddSingularRule("(octop|vir)i$", "$1us");
AddSingularRule("(alias|status)$", "$1");
AddSingularRule("(alias|status)es$", "$1");
AddSingularRule("^(ox)en", "$1");
AddSingularRule("(vert|ind)ices$", "$1ex");
AddSingularRule("(matr)ices$", "$1ix");
AddSingularRule("(quiz)zes$", "$1");
AddIrregularRule("person", "people");
AddIrregularRule("man", "men");
AddIrregularRule("child", "children");
AddIrregularRule("sex", "sexes");
AddIrregularRule("tax", "taxes");
AddIrregularRule("move", "moves");
AddUnknownCountRule("equipment");
AddUnknownCountRule("information");
AddUnknownCountRule("rice");
AddUnknownCountRule("money");
AddUnknownCountRule("species");
AddUnknownCountRule("series");
AddUnknownCountRule("fish");
AddUnknownCountRule("sheep");
}
/// <summary>
/// Adds the irregular rule.
/// </summary>
/// <param name="singular">The singular.</param>
/// <param name="plural">The plural.</param>
private static void AddIrregularRule(string singular, string plural) {
AddPluralRule(String.Concat("(", singular[0], ")", singular.Substring(1), "$"), String.Concat("$1", plural.Substring(1)));
AddSingularRule(String.Concat("(", plural[0], ")", plural.Substring(1), "$"), String.Concat("$1", singular.Substring(1)));
}
/// <summary>
/// Adds the unknown count rule.
/// </summary>
/// <param name="word">The word.</param>
private static void AddUnknownCountRule(string word) {
_uncountables.Add(word.ToLower());
}
/// <summary>
/// Adds the plural rule.
/// </summary>
/// <param name="rule">The rule.</param>
/// <param name="replacement">The replacement.</param>
private static void AddPluralRule(string rule, string replacement) {
_plurals.Add(new InflectorRule(rule, replacement));
}
/// <summary>
/// Adds the singular rule.
/// </summary>
/// <param name="rule">The rule.</param>
/// <param name="replacement">The replacement.</param>
private static void AddSingularRule(string rule, string replacement) {
_singulars.Add(new InflectorRule(rule, replacement));
}
/// <summary>
/// Makes the plural.
/// </summary>
/// <param name="word">The word.</param>
/// <returns></returns>
public static string MakePlural(string word) {
return ApplyRules(_plurals, word);
}
/// <summary>
/// Makes the singular.
/// </summary>
/// <param name="word">The word.</param>
/// <returns></returns>
public static string MakeSingular(string word) {
return ApplyRules(_singulars, word);
}
/// <summary>
/// Applies the rules.
/// </summary>
/// <param name="rules">The rules.</param>
/// <param name="word">The word.</param>
/// <returns></returns>
private static string ApplyRules(IList<InflectorRule> rules, string word) {
string result = word;
if (!_uncountables.Contains(word.ToLower())) {
for (int i = rules.Count - 1; i >= 0; i--) {
string currentPass = rules[i].Apply(word);
if (currentPass != null) {
result = currentPass;
break;
}
}
}
return result;
}
/// <summary>
/// Converts the string to title case.
/// </summary>
/// <param name="word">The word.</param>
/// <returns></returns>
public static string ToTitleCase(string word) {
return Regex.Replace(ToHumanCase(AddUnderscores(word)), @"\b([a-z])",
delegate(Match match) { return match.Captures[0].Value.ToUpper(); });
}
/// <summary>
/// Converts the string to human case.
/// </summary>
/// <param name="lowercaseAndUnderscoredWord">The lowercase and underscored word.</param>
/// <returns></returns>
public static string ToHumanCase(string lowercaseAndUnderscoredWord) {
return MakeInitialCaps(Regex.Replace(lowercaseAndUnderscoredWord, @"_", " "));
}
/// <summary>
/// Adds the underscores.
/// </summary>
/// <param name="pascalCasedWord">The pascal cased word.</param>
/// <returns></returns>
public static string AddUnderscores(string pascalCasedWord) {
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();
}
/// <summary>
/// Makes the initial caps.
/// </summary>
/// <param name="word">The word.</param>
/// <returns></returns>
public static string MakeInitialCaps(string word) {
return String.Concat(word.Substring(0, 1).ToUpper(), word.Substring(1).ToLower());
}
/// <summary>
/// Makes the initial lower case.
/// </summary>
/// <param name="word">The word.</param>
/// <returns></returns>
public static string MakeInitialLowerCase(string word) {
return String.Concat(word.Substring(0, 1).ToLower(), word.Substring(1));
}
/// <summary>
/// Determine whether the passed string is numeric, by attempting to parse it to a double
/// </summary>
/// <param name="str">The string to evaluated for numeric conversion</param>
/// <returns>
/// <c>true</c> if the string can be converted to a number; otherwise, <c>false</c>.
/// </returns>
public static bool IsStringNumeric(string str) {
double result;
return (double.TryParse(str, NumberStyles.Float, NumberFormatInfo.CurrentInfo, out result));
}
/// <summary>
/// Adds the ordinal suffix.
/// </summary>
/// <param name="number">The number.</param>
/// <returns></returns>
public static string AddOrdinalSuffix(string number) {
if (IsStringNumeric(number)) {
int n = int.Parse(number);
int nMod100 = n % 100;
if (nMod100 >= 11 && nMod100 <= 13)
return String.Concat(number, "th");
switch (n % 10) {
case 1:
return String.Concat(number, "st");
case 2:
return String.Concat(number, "nd");
case 3:
return String.Concat(number, "rd");
default:
return String.Concat(number, "th");
}
}
return number;
}
/// <summary>
/// Converts the underscores to dashes.
/// </summary>
/// <param name="underscoredWord">The underscored word.</param>
/// <returns></returns>
public static string ConvertUnderscoresToDashes(string underscoredWord) {
return underscoredWord.Replace('_', '-');
}
#region Nested type: InflectorRule
/// <summary>
/// Summary for the InflectorRule class
/// </summary>
private class InflectorRule {
/// <summary>
///
/// </summary>
public readonly Regex regex;
/// <summary>
///
/// </summary>
public readonly string replacement;
/// <summary>
/// Initializes a new instance of the <see cref="InflectorRule"/> class.
/// </summary>
/// <param name="regexPattern">The regex pattern.</param>
/// <param name="replacementText">The replacement text.</param>
public InflectorRule(string regexPattern, string replacementText) {
regex = new Regex(regexPattern, RegexOptions.IgnoreCase);
replacement = replacementText;
}
/// <summary>
/// Applies the specified word.
/// </summary>
/// <param name="word">The word.</param>
/// <returns></returns>
public string Apply(string word) {
if (!regex.IsMatch(word))
return null;
string replace = regex.Replace(word, replacement);
if (word == word.ToUpper())
replace = replace.ToUpper();
return replace;
}
}
#endregion
}
#>
\ No newline at end of file

\ No newline at end of file
<#@ template language="C#v3.5" debug="False" hostspecific="True" #>
<#@ output extension=".cs" #>
<#@ include file="SQLServer.ttinclude" #>
<#
var sps = GetSPs();
if(sps.Count>0){
#>
using System;
using SubSonic;
using SubSonic.Schema;
using SubSonic.DataProviders;
using System.Data;
namespace <#=Namespace#>{
public partial class <#=DatabaseName#>DB{
<# foreach(var sp in sps){#>
public StoredProcedure <#=sp.CleanName#>(<#=sp.ArgList#>){
StoredProcedure sp=new StoredProcedure("<#=sp.Name#>",this.Provider);
<# foreach(var par in sp.Parameters){#>
sp.Command.AddParameter("<#=par.Name#>",<#=par.CleanName#>,DbType.<#=par.DbType#>);
<# }#>
return sp;
}
<# }#>
}
}
<# }#>
\ No newline at end of file
using System;
using SubSonic.Schema;
using System.Collections.Generic;
using SubSonic.DataProviders;
using System.Data;
namespace SubSonic {
/// <summary>
/// Table: Posts
/// Primary Key: Id
/// </summary>
public class PostsTable: DatabaseTable {
public PostsTable(IDataProvider provider):base("Posts",provider){
ClassName = "Post";
SchemaName = "dbo";
Columns.Add(new DatabaseColumn("Id", this)
{
IsPrimaryKey = true,
DataType = DbType.Int32,
IsNullable = false,
AutoIncrement = true,
IsForeignKey = false,
MaxLength = 0
});
Columns.Add(new DatabaseColumn("Text", this)
{
IsPrimaryKey = false,
DataType = DbType.AnsiString,
IsNullable = false,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = -1
});
Columns.Add(new DatabaseColumn("CreationDate", this)
{
IsPrimaryKey = false,
DataType = DbType.DateTime,
IsNullable = false,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = 0
});
Columns.Add(new DatabaseColumn("LastChangeDate", this)
{
IsPrimaryKey = false,
DataType = DbType.DateTime,
IsNullable = false,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = 0
});
Columns.Add(new DatabaseColumn("Counter1", this)
{
IsPrimaryKey = false,
DataType = DbType.Int32,
IsNullable = true,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = 0
});
Columns.Add(new DatabaseColumn("Counter2", this)
{
IsPrimaryKey = false,
DataType = DbType.Int32,
IsNullable = true,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = 0
});
Columns.Add(new DatabaseColumn("Counter3", this)
{
IsPrimaryKey = false,
DataType = DbType.Int32,
IsNullable = true,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = 0
});
Columns.Add(new DatabaseColumn("Counter4", this)
{
IsPrimaryKey = false,
DataType = DbType.Int32,
IsNullable = true,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = 0
});
Columns.Add(new DatabaseColumn("Counter5", this)
{
IsPrimaryKey = false,
DataType = DbType.Int32,
IsNullable = true,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = 0
});
Columns.Add(new DatabaseColumn("Counter6", this)
{
IsPrimaryKey = false,
DataType = DbType.Int32,
IsNullable = true,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = 0
});
Columns.Add(new DatabaseColumn("Counter7", this)
{
IsPrimaryKey = false,
DataType = DbType.Int32,
IsNullable = true,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = 0
});
Columns.Add(new DatabaseColumn("Counter8", this)
{
IsPrimaryKey = false,
DataType = DbType.Int32,
IsNullable = true,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = 0
});
Columns.Add(new DatabaseColumn("Counter9", this)
{
IsPrimaryKey = false,
DataType = DbType.Int32,
IsNullable = true,
AutoIncrement = false,
IsForeignKey = false,
MaxLength = 0
});
}
public IColumn Id{
get{
return this.GetColumn("Id");
}
}
public static string IdColumn{
get{
return "Id";
}
}
public IColumn Text{
get{
return this.GetColumn("Text");
}
}
public static string TextColumn{
get{
return "Text";
}
}
public IColumn CreationDate{
get{
return this.GetColumn("CreationDate");
}
}
public static string CreationDateColumn{
get{
return "CreationDate";
}
}
public IColumn LastChangeDate{
get{
return this.GetColumn("LastChangeDate");
}
}
public static string LastChangeDateColumn{
get{
return "LastChangeDate";
}
}
public IColumn Counter1{
get{
return this.GetColumn("Counter1");
}
}
public static string Counter1Column{
get{
return "Counter1";
}
}
public IColumn Counter2{
get{
return this.GetColumn("Counter2");
}
}
public static string Counter2Column{
get{
return "Counter2";
}
}
public IColumn Counter3{
get{
return this.GetColumn("Counter3");
}
}
public static string Counter3Column{
get{
return "Counter3";
}
}
public IColumn Counter4{
get{
return this.GetColumn("Counter4");
}
}
public static string Counter4Column{
get{
return "Counter4";
}
}
public IColumn Counter5{
get{
return this.GetColumn("Counter5");
}
}
public static string Counter5Column{
get{
return "Counter5";
}
}
public IColumn Counter6{
get{
return this.GetColumn("Counter6");
}
}
public static string Counter6Column{
get{
return "Counter6";
}
}
public IColumn Counter7{
get{
return this.GetColumn("Counter7");
}
}
public static string Counter7Column{
get{
return "Counter7";
}
}
public IColumn Counter8{
get{
return this.GetColumn("Counter8");
}
}
public static string Counter8Column{
get{
return "Counter8";
}
}
public IColumn Counter9{
get{
return this.GetColumn("Counter9");
}
}
public static string Counter9Column{
get{
return "Counter9";
}
}
}
}
\ No newline at end of file
<#@ template language="C#v3.5" debug="False" hostspecific="True" #>
<#@ output extension=".cs" #>
<#@ include file="SQLServer.ttinclude" #>
<#
var tables = LoadTables();
#>
using System;
using SubSonic.Schema;
using System.Collections.Generic;
using SubSonic.DataProviders;
using System.Data;
namespace <#=Namespace#> {
<# foreach(var tbl in tables){
if(!ExcludeTables.Contains(tbl.Name))
{
#>
/// <summary>
/// Table: <#=tbl.Name#>
/// Primary Key: <#=tbl.PrimaryKey#>
/// </summary>
public class <#=tbl.CleanName#>Table: DatabaseTable {
public <#=tbl.CleanName#>Table(IDataProvider provider):base("<#=tbl.Name#>",provider){
ClassName = "<#=tbl.ClassName#>";
SchemaName = "<#=tbl.Schema ?? ""#>";
<# foreach(var col in tbl.Columns){#>
Columns.Add(new DatabaseColumn("<#=col.Name#>", this)
{
IsPrimaryKey = <#=col.IsPK.ToString().ToLower()#>,
DataType = DbType.<#=col.DbType.ToString()#>,
IsNullable = <#=col.IsNullable.ToString().ToLower()#>,
AutoIncrement = <#=col.AutoIncrement.ToString().ToLower()#>,
IsForeignKey = <#=col.IsForeignKey.ToString().ToLower()#>,
MaxLength = <#=col.MaxLength#>
});
<# }#>
}
<# foreach(var col in tbl.Columns){#>
public IColumn <#=col.CleanName#>{
get{
return this.GetColumn("<#=col.Name#>");
}
}
public static string <#= col.CleanName #>Column{
get{
return "<#= col.Name #>";
}
}
<# }#>
}
<#
}
}
#>
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment