mirror of https://github.com/Sonarr/Sonarr
Updated PetaPoco with Exists, AddMany,UpdateMany,InsertMany,SaveMany
This commit is contained in:
parent
3cccb5858a
commit
dd55a055e6
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Data.SQLite;
|
||||
using System.IO;
|
||||
using MvcMiniProfiler.Data;
|
||||
|
@ -58,9 +60,12 @@ namespace NzbDrone.Core.Datastore
|
|||
public static IDatabase GetPetaPocoDb(string connectionString)
|
||||
{
|
||||
var profileConnection = ProfiledDbConnection.Get(new SQLiteConnection(connectionString));
|
||||
PetaPoco.Database.Mapper = new CustomeMapper();
|
||||
var db = new PetaPoco.Database(profileConnection);
|
||||
db.OpenSharedConnection();
|
||||
|
||||
Database.Mapper = new CustomeMapper();
|
||||
var db = new Database(profileConnection);
|
||||
|
||||
if (profileConnection.State != ConnectionState.Open)
|
||||
profileConnection.Open();
|
||||
|
||||
return db;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* PetaPoco v4.0.2 - A Tiny ORMish thing for your POCO's.
|
||||
* Copyright © 2011 Topten Software. All Rights Reserved.
|
||||
* Copyright © 2011 Topten Software. All Rights Reserved.
|
||||
*
|
||||
* Apache License 2.0 - http://www.toptensoftware.com/petapoco/license
|
||||
*
|
||||
|
@ -24,7 +24,6 @@ using System.Reflection.Emit;
|
|||
using System.Linq.Expressions;
|
||||
|
||||
|
||||
// ReSharper disable
|
||||
namespace PetaPoco
|
||||
{
|
||||
// Poco's marked [Explicit] require all column properties to be marked
|
||||
|
@ -182,6 +181,8 @@ namespace PetaPoco
|
|||
List<T> Fetch<T>(long page, long itemsPerPage, Sql sql);
|
||||
Page<T> Page<T>(long page, long itemsPerPage, string sql, params object[] args);
|
||||
Page<T> Page<T>(long page, long itemsPerPage, Sql sql);
|
||||
List<T> SkipTake<T>(long skip, long take, string sql, params object[] args);
|
||||
List<T> SkipTake<T>(long skip, long take, Sql sql);
|
||||
List<TRet> Fetch<T1, T2, TRet>(Func<T1, T2, TRet> cb, string sql, params object[] args);
|
||||
List<TRet> Fetch<T1, T2, T3, TRet>(Func<T1, T2, T3, TRet> cb, string sql, params object[] args);
|
||||
List<TRet> Fetch<T1, T2, T3, T4, TRet>(Func<T1, T2, T3, T4, TRet> cb, string sql, params object[] args);
|
||||
|
@ -221,13 +222,14 @@ namespace PetaPoco
|
|||
T FirstOrDefault<T>(Sql sql);
|
||||
bool Exists<T>(object primaryKey);
|
||||
int OneTimeCommandTimeout { get; set; }
|
||||
bool Exists<T>(string sql, params object[] args);
|
||||
}
|
||||
|
||||
public interface IDatabase : IDatabaseQuery
|
||||
{
|
||||
void Dispose();
|
||||
IDbConnection Connection { get; }
|
||||
Transaction GetTransaction();
|
||||
ITransaction GetTransaction();
|
||||
void BeginTransaction();
|
||||
void AbortTransaction();
|
||||
void CompleteTransaction();
|
||||
|
@ -240,6 +242,7 @@ namespace PetaPoco
|
|||
int Update(object poco, object primaryKeyValue);
|
||||
int Update<T>(string sql, params object[] args);
|
||||
int Update<T>(Sql sql);
|
||||
void UpdateMany<T>(IEnumerable<T> pocoList);
|
||||
int Delete(string tableName, string primaryKeyName, object poco);
|
||||
int Delete(string tableName, string primaryKeyName, object poco, object primaryKeyValue);
|
||||
int Delete(object poco);
|
||||
|
@ -248,6 +251,8 @@ namespace PetaPoco
|
|||
int Delete<T>(object pocoOrPrimaryKey);
|
||||
void Save(string tableName, string primaryKeyName, object poco);
|
||||
void Save(object poco);
|
||||
void InsertMany<T>(IEnumerable<T> pocoList);
|
||||
void SaveMany<T>(IEnumerable<T> pocoList);
|
||||
}
|
||||
|
||||
// Database class ... this is where most of the action happens
|
||||
|
@ -353,19 +358,17 @@ namespace PetaPoco
|
|||
{
|
||||
_sharedConnection = _factory.CreateConnection();
|
||||
_sharedConnection.ConnectionString = _connectionString;
|
||||
_sharedConnection.Open();
|
||||
|
||||
if (KeepConnectionAlive)
|
||||
_sharedConnectionDepth++; // Make sure you call Dispose
|
||||
}
|
||||
|
||||
if (_sharedConnection.State != ConnectionState.Open)
|
||||
_sharedConnection.Open();
|
||||
|
||||
_sharedConnectionDepth++;
|
||||
|
||||
}
|
||||
|
||||
// Close a previously opened connection
|
||||
/// <summary>
|
||||
/// Close a previously opened connection
|
||||
/// </summary>
|
||||
public void CloseSharedConnection()
|
||||
{
|
||||
if (_sharedConnectionDepth > 0)
|
||||
|
@ -386,7 +389,7 @@ namespace PetaPoco
|
|||
}
|
||||
|
||||
// Helper to create a transaction scope
|
||||
public Transaction GetTransaction()
|
||||
public ITransaction GetTransaction()
|
||||
{
|
||||
return new Transaction(this);
|
||||
}
|
||||
|
@ -750,7 +753,7 @@ namespace PetaPoco
|
|||
|
||||
static Regex rxColumns = new Regex(@"\A\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)
|
||||
public static bool SplitSqlForPaging<T>(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
|
||||
{
|
||||
sqlSelectRemoved = null;
|
||||
sqlCount = null;
|
||||
|
@ -766,26 +769,32 @@ namespace PetaPoco
|
|||
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
|
||||
// Look for an "ORDER BY <whatever>" clause or primarykey from pocodata
|
||||
var data = PocoData.ForType(typeof(T));
|
||||
|
||||
m = rxOrderBy.Match(sqlCount);
|
||||
if (!m.Success)
|
||||
if (!m.Success
|
||||
&& (string.IsNullOrEmpty(data.TableInfo.PrimaryKey) ||
|
||||
(!data.TableInfo.PrimaryKey.Split(',').All(x => data.Columns.Values.Any(y => y.ColumnName.Equals(x, StringComparison.OrdinalIgnoreCase))))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
g = m.Groups[0];
|
||||
sqlOrderBy = g.ToString();
|
||||
sqlOrderBy = m.Success ? g.ToString() : "ORDER BY " + data.TableInfo.PrimaryKey;
|
||||
sqlCount = sqlCount.Substring(0, g.Index) + sqlCount.Substring(g.Index + g.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void BuildPageQueries<T>(long page, long itemsPerPage, string sql, ref object[] args, out string sqlCount, out string sqlPage)
|
||||
private void BuildPageQueries<T>(long skip, long take, string sql, ref object[] args, out string sqlCount, out string sqlPage)
|
||||
{
|
||||
// Add auto select clause
|
||||
sql = AddSelectClause<T>(sql);
|
||||
|
||||
// Split the SQL into the bits we need
|
||||
string sqlSelectRemoved, sqlOrderBy;
|
||||
if (!SplitSqlForPaging(sql, out sqlCount, out sqlSelectRemoved, out sqlOrderBy))
|
||||
if (!SplitSqlForPaging<T>(sql, out sqlCount, out sqlSelectRemoved, out sqlOrderBy))
|
||||
throw new Exception("Unable to parse SQL statement for paged query");
|
||||
if (_dbType == DBType.Oracle && sqlSelectRemoved.StartsWith("*"))
|
||||
throw new Exception("Query must alias '*' when performing a paged query.\neg. select t.* from table t order by t.id");
|
||||
|
@ -793,20 +802,21 @@ namespace PetaPoco
|
|||
// Build the SQL for the actual final result
|
||||
if (_dbType == DBType.SqlServer || _dbType == DBType.Oracle)
|
||||
{
|
||||
var fromIndex = sqlSelectRemoved.IndexOf("from", StringComparison.OrdinalIgnoreCase);
|
||||
sqlSelectRemoved = rxOrderBy.Replace(sqlSelectRemoved, "");
|
||||
sqlPage = string.Format("SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) peta_rn, {1}) peta_paged WHERE peta_rn>@{2} AND peta_rn<=@{3}",
|
||||
sqlOrderBy, sqlSelectRemoved, args.Length, args.Length + 1);
|
||||
args = args.Concat(new object[] { (page - 1) * itemsPerPage, page * itemsPerPage }).ToArray();
|
||||
sqlPage = string.Format("SELECT * FROM (SELECT {2}, ROW_NUMBER() OVER ({0}) peta_rn {1}) peta_paged WHERE peta_rn>@{3} AND peta_rn<=@{4}",
|
||||
sqlOrderBy, sqlSelectRemoved.Substring(fromIndex), sqlSelectRemoved.Substring(0, fromIndex - 1), args.Length, args.Length + 1);
|
||||
args = args.Concat(new object[] { skip, skip + take }).ToArray();
|
||||
}
|
||||
else if (_dbType == DBType.SqlServerCE)
|
||||
{
|
||||
sqlPage = string.Format("{0}\nOFFSET @{1} ROWS FETCH NEXT @{2} ROWS ONLY", sql, args.Length, args.Length + 1);
|
||||
args = args.Concat(new object[] { (page - 1) * itemsPerPage, itemsPerPage }).ToArray();
|
||||
args = args.Concat(new object[] { skip, take }).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlPage = string.Format("{0}\nLIMIT @{1} OFFSET @{2}", sql, args.Length, args.Length + 1);
|
||||
args = args.Concat(new object[] { itemsPerPage, (page - 1) * itemsPerPage }).ToArray();
|
||||
args = args.Concat(new object[] { take, skip }).ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -815,7 +825,11 @@ namespace PetaPoco
|
|||
public Page<T> Page<T>(long page, long itemsPerPage, string sql, params object[] args)
|
||||
{
|
||||
string sqlCount, sqlPage;
|
||||
BuildPageQueries<T>(page, itemsPerPage, sql, ref args, out sqlCount, out sqlPage);
|
||||
|
||||
long skip = (page - 1) * itemsPerPage;
|
||||
long take = itemsPerPage;
|
||||
|
||||
BuildPageQueries<T>(skip, take, sql, ref args, out sqlCount, out sqlPage);
|
||||
|
||||
// Save the one-time command time out and use it for both queries
|
||||
int saveTimeout = OneTimeCommandTimeout;
|
||||
|
@ -843,6 +857,21 @@ namespace PetaPoco
|
|||
return Page<T>(page, itemsPerPage, sql.SQL, sql.Arguments);
|
||||
}
|
||||
|
||||
public List<T> SkipTake<T>(long skip, long take, string sql, params object[] args)
|
||||
{
|
||||
string sqlCount, sqlPage;
|
||||
|
||||
BuildPageQueries<T>(skip, take, sql, ref args, out sqlCount, out sqlPage);
|
||||
|
||||
var result = Fetch<T>(sqlPage, args);
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<T> SkipTake<T>(long skip, long take, Sql sql)
|
||||
{
|
||||
return SkipTake<T>(skip, take, sql.SQL, sql.Arguments);
|
||||
}
|
||||
|
||||
// Return an enumerable collection of pocos
|
||||
public IEnumerable<T> Query<T>(string sql, params object[] args)
|
||||
{
|
||||
|
@ -1213,6 +1242,38 @@ namespace PetaPoco
|
|||
var primaryKeyValuePairs = GetPrimaryKeyValues(PocoData.ForType(typeof(T)).TableInfo.PrimaryKey, primaryKey);
|
||||
return FirstOrDefault<T>(string.Format("WHERE {0}", BuildPrimaryKeySql(primaryKeyValuePairs, ref index)), primaryKeyValuePairs.Select(x => x.Value).ToArray()) != null;
|
||||
}
|
||||
|
||||
|
||||
public bool Exists<T>(string sql, params object[] args)
|
||||
{
|
||||
var poco = PocoData.ForType(typeof(T)).TableInfo;
|
||||
|
||||
string existsTemplate;
|
||||
|
||||
switch (_dbType)
|
||||
{
|
||||
case DBType.SQLite:
|
||||
case DBType.MySql:
|
||||
{
|
||||
existsTemplate = "SELECT EXISTS (SELECT 1 FROM {0} WHERE {1})";
|
||||
break;
|
||||
}
|
||||
|
||||
case DBType.SqlServer:
|
||||
{
|
||||
existsTemplate = "IF EXISTS (SELECT 1 FROM {0} WHERE {1}) SELECT 1 ELSE SELECT 0";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
existsTemplate = "SELECT COUNT(*) FROM {0} WHERE {1}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ExecuteScalar<int>(string.Format(existsTemplate, poco.TableName, sql), args) != 0;
|
||||
}
|
||||
public T Single<T>(object primaryKey)
|
||||
{
|
||||
var index = 0;
|
||||
|
@ -1297,7 +1358,6 @@ namespace PetaPoco
|
|||
{
|
||||
using (var cmd = CreateCommand(_sharedConnection, ""))
|
||||
{
|
||||
|
||||
var pd = PocoData.ForObject(poco, primaryKeyName);
|
||||
var names = new List<string>();
|
||||
var values = new List<string>();
|
||||
|
@ -1466,6 +1526,19 @@ namespace PetaPoco
|
|||
return Insert(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, pd.TableInfo.AutoIncrement, poco);
|
||||
}
|
||||
|
||||
public void InsertMany<T>(IEnumerable<T> pocoList)
|
||||
{
|
||||
using (var tran = GetTransaction())
|
||||
{
|
||||
foreach (var poco in pocoList)
|
||||
{
|
||||
Insert(poco);
|
||||
}
|
||||
|
||||
tran.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -1617,6 +1690,20 @@ namespace PetaPoco
|
|||
return Execute(new Sql(string.Format("UPDATE {0}", EscapeTableName(pd.TableInfo.TableName))).Append(sql));
|
||||
}
|
||||
|
||||
public void UpdateMany<T>(IEnumerable<T> pocoList)
|
||||
{
|
||||
using (var tran = GetTransaction())
|
||||
{
|
||||
foreach (var poco in pocoList)
|
||||
{
|
||||
Update(poco);
|
||||
}
|
||||
|
||||
tran.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int Delete(string tableName, string primaryKeyName, object poco)
|
||||
{
|
||||
return Delete(tableName, primaryKeyName, poco, null);
|
||||
|
@ -1747,6 +1834,19 @@ namespace PetaPoco
|
|||
Save(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco);
|
||||
}
|
||||
|
||||
public void SaveMany<T>(IEnumerable<T> pocoList)
|
||||
{
|
||||
using (var tran = GetTransaction())
|
||||
{
|
||||
foreach (var poco in pocoList)
|
||||
{
|
||||
Save(poco);
|
||||
}
|
||||
|
||||
tran.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
public int CommandTimeout { get; set; }
|
||||
public int OneTimeCommandTimeout { get; set; }
|
||||
|
||||
|
@ -2269,7 +2369,12 @@ namespace PetaPoco
|
|||
}
|
||||
|
||||
// Transaction object helps maintain transaction depth counts
|
||||
public class Transaction : IDisposable
|
||||
public interface ITransaction : IDisposable
|
||||
{
|
||||
void Complete();
|
||||
}
|
||||
|
||||
public class Transaction : ITransaction
|
||||
{
|
||||
public Transaction(Database db)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue