This commit is contained in:
2025-07-15 12:20:55 +01:00
parent ecf48ba8b4
commit c28d2c6060
3 changed files with 232 additions and 43 deletions

View File

@@ -78,7 +78,8 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
//
public Dictionary<int, Model.Stock.StockJournalBuilder> ReadStockJournal(
List<int> stockJournalIds = null, List<int> stockIds = null, List<int> stockNumbers = null, DateTime? minEntryDate = null, DateTime? maxEntryDate = null)
List<int> stockJournalIds = null, List<int> stockIds = null, List<string> stockNumbers = null
, DateTime? minEntryDate = null, DateTime? maxEntryDate = null, List<int> stockStatusIds = null)
{
var returnDict = new Dictionary<int, Model.Stock.StockJournalBuilder>();
var sqlWhere = new SqlWhereBuilder();
@@ -97,39 +98,41 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
tblStockJournalPost.StockStatusID,
tblStockJournalPost.Quantity,
FROM tblStockJournal
LEFT OUTER JOIN
tblStock
ON tblStockJournal.StockID = tblStock.StockID
LEFT OUTER JOIN
tblStockJournalPost
ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
LEFT OUTER JOIN tblStock ON tblStockJournal.StockID = tblStock.StockID
LEFT OUTER JOIN tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
WHERE 1=1 ";
// build where clause based on provided filters
bool noFilter = true;
if (stockJournalIds != null && stockJournalIds.Any())
{
sqlWhere.In("tblStockJournal.StockJournalID", stockJournalIds, "AND");
sql += sqlWhere.InClause("tblStockJournal.StockJournalID", stockJournalIds, "AND");
noFilter = false;
}
if (stockIds != null && stockIds.Any())
{
sqlWhere.In("tblStockJournal.StockID", stockIds, "AND");
sql += sqlWhere.InClause("tblStockJournal.StockID", stockIds, "AND");
noFilter = false;
}
if (stockNumbers != null && stockNumbers.Any())
{
sqlWhere.In("tblStock.StockNumber", stockNumbers, "AND");
sql += sqlWhere.InClause("tblStock.StockNumber", stockNumbers, "AND");
noFilter = false;
}
if (minEntryDate.HasValue)
{
sqlWhere.IsEqualToOrGreaterThan("tblStockJournal.EntryDate", minEntryDate.Value.ToUniversalTime(), "AND");
sql += sqlWhere.IsEqualToOrGreaterThanClause("tblStockJournal.EntryDate", minEntryDate.Value.ToUniversalTime(), "AND");
noFilter = false;
}
if (maxEntryDate.HasValue)
{
sqlWhere.IsEqualToOrLessThan("tblStockJournal.EntryDate", maxEntryDate.Value.ToUniversalTime(), "AND");
sql += sqlWhere.IsEqualToOrLessThanClause("tblStockJournal.EntryDate", maxEntryDate.Value.ToUniversalTime(), "AND");
noFilter = false;
}
if (stockStatusIds != null && stockStatusIds.Any())
{
sql = sql + Environment.NewLine + " AND tblStockJournal.StockJournalID IN (SELECT StockJournalID FROM tblStockJournalPost WHERE "
+ sqlWhere.InClause("StockStatusID", stockStatusIds) + " ) ";
noFilter = false;
}
if (noFilter)
@@ -137,7 +140,7 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
throw new ArgumentException("At least one filter must be provided for stock journal retrieval.");
}
sql += sqlWhere.SqlWhereString + " ORDER BY tblStockJournal.EntryDate, tblStockJournal.StockJournalID, tblStockJournalPost.StockJournalPostID;";
sql += " ORDER BY tblStockJournal.EntryDate, tblStockJournal.StockJournalID, tblStockJournalPost.StockJournalPostID;";
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{

View File

@@ -10,17 +10,15 @@ using Microsoft.IdentityModel.Tokens;
namespace bnhtrade.Core.Data.Database
{
/// <summary>
/// Step 1: Call the methods for each where clause you want to create. This can be done multiple times to create an sql where string. Pay attention
/// to the prefixes that you'll require between each where clause, as each time a method is called the sql statement will be appended to the previous sql
/// string.
/// Sep 1: Call each Where_____ method in this class as needed, the method returns a string that can be appended to your SQL statement and builds
/// a parameter list.
///
/// Step 2: Appened the created sql string to your sql statement, NB the WHERE statemet is not included by default.
///
/// Step 3: Once you've created your sql command object, add the parameters to it using the method contained within this class.
/// Step 2: Once you've created your sql command object, add the parameters to it using the method contained within this class.
///
/// Step 4: exceute your sql commend.
/// </summary>
public class SqlWhereBuilder
internal class SqlWhereBuilder
{
private int parameterCount = 0;
@@ -29,8 +27,10 @@ namespace bnhtrade.Core.Data.Database
Init();
}
[Obsolete("Deprecated. Use the new methods.")]
public string SqlWhereString { get; private set; }
[Obsolete("Deprecated. Use the new methods.")]
public bool IsSetSqlWhereString
{
get
@@ -117,6 +117,7 @@ namespace bnhtrade.Core.Data.Database
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
/// <param name="phraseList">List of phrases to test in condition statement</param>
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
[Obsolete("Deprecated. Use the new methods.")]
public void LikeAnd(string columnReference, IEnumerable<string> phraseList, string wherePrefix = null)
{
Like(columnReference, phraseList, true, wherePrefix);
@@ -128,11 +129,13 @@ namespace bnhtrade.Core.Data.Database
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
/// <param name="phraseList">List of phrases to test in condition statement</param>
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
[Obsolete("Deprecated. Use the new methods.")]
public void LikeOr(string columnReference, IEnumerable<string> phraseList, string wherePrefix = null)
{
Like(columnReference, phraseList, false, wherePrefix);
}
[Obsolete("Deprecated. Use the new methods.")]
private void Like(string columnReference, IEnumerable<string> phraseList, bool isAnd, string wherePrefix = null)
{
if (phraseList == null || !phraseList.Any())
@@ -216,21 +219,25 @@ namespace bnhtrade.Core.Data.Database
// SqlWhereString = SqlWhereString + sqlWhereString;
//}
[Obsolete("Deprecated. Use the new methods.")]
public void IsEqualTo(string columnReference, object whereArgument, string wherePrefix = null)
{
IsEqualSub(columnReference, whereArgument, "=", wherePrefix);
}
[Obsolete("Deprecated. Use the new methods.")]
public void IsEqualToOrLessThan(string columnReference, object whereArgument, string wherePrefix = null)
{
IsEqualSub(columnReference, whereArgument, "<=", wherePrefix);
}
[Obsolete("Deprecated. Use the new methods.")]
public void IsEqualToOrGreaterThan(string columnReference, object whereArgument, string wherePrefix = null)
{
IsEqualSub(columnReference, whereArgument, ">=", wherePrefix);
}
[Obsolete("Deprecated. Use the new methods.")]
private void IsEqualSub(string columnReference, object whereArgument, string operatorString, string wherePrefix = null)
{
if (string.IsNullOrEmpty(columnReference))
@@ -262,16 +269,17 @@ namespace bnhtrade.Core.Data.Database
/// Append an 'In' statement and parameter list to the class properties
/// </summary>
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
/// <param name="orValueList">List of values to test in condition statement</param>
/// <param name="orArgumentList">List of values to test in condition statement</param>
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
public void In(string columnReference, IEnumerable<object> orValueList, string wherePrefix = null)
[Obsolete("Deprecated. Use the new methods.")]
public void In(string columnReference, IEnumerable<object> orArgumentList, string wherePrefix = null)
{
if (orValueList == null || !orValueList.Any())
if (orArgumentList == null || !orArgumentList.Any())
{
return;
}
var distinctList = orValueList.Distinct().ToList();
var distinctList = orArgumentList.Distinct().ToList();
string sqlWhere = @"
";
@@ -302,15 +310,16 @@ namespace bnhtrade.Core.Data.Database
/// Append an 'In' statement and parameter list to the class properties
/// </summary>
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
/// <param name="orValueList">List of values to test in condition statement</param>
/// <param name="orArgumentList">List of values to test in condition statement</param>
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
public void In(string columnReference, IEnumerable<string> orValueList, string wherePrefix = null)
[Obsolete("Deprecated. Use the new methods.")]
public void In(string columnReference, IEnumerable<string> orArgumentList, string wherePrefix = null)
{
var objectList = new List<object>();
if (orValueList != null && orValueList.Any())
if (orArgumentList != null && orArgumentList.Any())
{
foreach (string value in orValueList)
foreach (string value in orArgumentList)
{
objectList.Add(value.ToString());
}
@@ -323,15 +332,16 @@ namespace bnhtrade.Core.Data.Database
/// Append an 'In' statement and parameter list to the class properties
/// </summary>
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
/// <param name="orValueList">List of values to test in condition statement</param>
/// <param name="orArgumentList">List of values to test in condition statement</param>
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
public void In(string columnReference, IEnumerable<int> orValueList, string wherePrefix = null)
[Obsolete("Deprecated. Use the new methods.")]
public void In(string columnReference, IEnumerable<int> orArgumentList, string wherePrefix = null)
{
var objectList = new List<object>();
if (orValueList != null && orValueList.Any())
if (orArgumentList != null && orArgumentList.Any())
{
foreach (var value in orValueList)
foreach (var value in orArgumentList)
{
objectList.Add(value.ToString());
}
@@ -344,15 +354,16 @@ namespace bnhtrade.Core.Data.Database
/// Append an 'In' statement and parameter list to the class properties
/// </summary>
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
/// <param name="orValueList">List of values to test in condition statement</param>
/// <param name="orArgumentList">List of values to test in condition statement</param>
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
public void In(string columnReference, IEnumerable<uint> orValueList, string wherePrefix = null)
[Obsolete("Deprecated. Use the new methods.")]
public void In(string columnReference, IEnumerable<uint> orArgumentList, string wherePrefix = null)
{
var objectList = new List<object>();
if (orValueList != null && orValueList.Any())
if (orArgumentList != null && orArgumentList.Any())
{
foreach (var value in orValueList)
foreach (var value in orArgumentList)
{
objectList.Add(value.ToString());
}
@@ -361,13 +372,14 @@ namespace bnhtrade.Core.Data.Database
In(columnReference, objectList, wherePrefix);
}
public void In(string columnReference, IEnumerable<DateTime> orValueList, string wherePrefix = null)
[Obsolete("Deprecated. Use the new methods.")]
public void In(string columnReference, IEnumerable<DateTime> orArgumentList, string wherePrefix = null)
{
var objectList = new List<object>();
if (orValueList != null && orValueList.Any())
if (orArgumentList != null && orArgumentList.Any())
{
foreach(var value in orValueList)
foreach(var value in orArgumentList)
{
objectList.Add(value.ToString());
}
@@ -376,17 +388,188 @@ namespace bnhtrade.Core.Data.Database
In(columnReference, objectList, wherePrefix);
}
//
// new code below, going to change everything over to these methods, it returns the sql string instead of appending it to the class property
// which is more versatile and more intuitive to use
//
/// <summary>
/// Append an 'Like' statement (with AND between each like string) and parameter list to the class properties
/// </summary>
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
/// <param name="arguments">List of phrases to test in condition statement</param>
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
public string LikeAndClause(string columnReference, IEnumerable<string> arguments, string clausePrefix = null, string clausePostfix = null)
{
return LikeClause(columnReference, arguments, true, clausePrefix, clausePostfix);
}
/// <summary>
/// Append an 'Like' statement (with OR between each like string) and parameter list to the class properties
/// </summary>
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
/// <param name="phraseList">List of phrases to test in condition statement</param>
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
public string LikeOrClause(string columnReference, IEnumerable<string> arguments, string clausePrefix = null, string clausePostfix = null)
{
return LikeClause(columnReference, arguments, false, clausePrefix, clausePostfix);
}
private string LikeClause(string columnReference, IEnumerable<string> arguments, bool isAnd, string clausePrefix = null, string clausePostfix = null)
{
if (arguments == null || !arguments.Any())
{
throw new ArgumentException("The arguments cannot be null or empty.", nameof(arguments));
}
// ensure no values are repeated
var distinctList = arguments.Distinct().ToList();
// clean the list
for (int i = 0; i < distinctList.Count; i++)
{
if (string.IsNullOrEmpty(distinctList[i]))
{
distinctList.RemoveAt(i);
i--;
}
}
// check again
if (distinctList == null || !distinctList.Any())
{
throw new ArgumentException("The arguments must contain at least one valid value.", nameof(arguments));
}
string sqlWhere = Environment.NewLine + clausePrefix + " ";
int listCount = distinctList.Count();
for (int i = 0; i < listCount; i++)
{
if (i > 0)
{
if (isAnd)
{
sqlWhere += " AND ";
}
else
{
sqlWhere += " OR ";
}
}
sqlWhere += " ( " + columnReference + " LIKE '%' + ";
sqlWhere = sqlWhere + GetSetParameter(distinctList[i]) + " + '%' ) ";
}
return sqlWhere + clausePostfix;
}
public string IsEqualToClause(string columnReference, object whereArgument, string clausePrefix = null, string clausePostfix = null)
{
return IsEqualSubClause(columnReference, whereArgument, "=", clausePrefix, clausePostfix);
}
public string IsEqualToOrLessThanClause(string columnReference, object whereArgument, string clausePrefix = null, string clausePostfix = null)
{
return IsEqualSubClause(columnReference, whereArgument, "<=", clausePrefix, clausePostfix);
}
public string IsEqualToOrGreaterThanClause(string columnReference, object whereArgument, string clausePrefix = null, string clausePostfix = null)
{
return IsEqualSubClause(columnReference, whereArgument, ">=", clausePrefix, clausePostfix);
}
private string IsEqualSubClause(string columnReference, object whereArgument, string operatorString, string clausePrefix = null, string clausePostfix = null)
{
if (string.IsNullOrEmpty(columnReference))
{
throw new Exception(" WhereIsEqual* method requires a valid column reference.");
}
if (whereArgument == null)
{
throw new Exception(" WhereIsEqual* method requires a valid where argument.");
}
if (whereArgument is string && string.IsNullOrEmpty(whereArgument.ToString()))
{
throw new Exception(" WhereIsEqual* method requires a valid where argument.");
}
// build the SQL WHERE clause and parameter list
string sqlWhere = Environment.NewLine + clausePrefix + " ( " + columnReference + " " + operatorString + " " + GetSetParameter(whereArgument) + " ) ";
return sqlWhere + clausePostfix;
}
/// <summary>
/// Constructs a SQL WHERE clause with an IN condition for the specified column and a list of values and adds to the parameter list.
/// </summary>
/// <param name="columnReference">The name of the column to be used in the IN condition</param>
/// <param name="orArgumentList">A collection of values to include in the IN condition.</param>
/// <param name="lineReturn">A boolean value indicating whether to prefix the returned SQL clause with a line return</param>
/// <returns>A string representing the SQL WHERE clause with the specified column and values in the IN condition.</returns>
public string InClause<T>(string columnReference, IEnumerable<T> orArgumentList, string clausePrefix = null, string clausePostfix = null)
{
// new code, going to change everything over to this method, it returns the sql string instead of appending it to the class property
// which is more versatile and more intuitive to use
if (string.IsNullOrEmpty(columnReference))
{
throw new ArgumentException("Column reference cannot be null or empty.", nameof(columnReference));
}
if (orArgumentList == null || !orArgumentList.Any())
{
throw new ArgumentException("The orArgumentList cannot be null or empty.", nameof(orArgumentList));
}
// ensure no values are repeated, null, or empty
var distinctList = orArgumentList
.Where(x =>
x is not null && // not null
(!(x.GetType().IsGenericType && x.GetType().GetGenericTypeDefinition() == typeof(Nullable<>)) // not a nullable type
|| x.GetType().GetProperty("HasValue")?.GetValue(x) as bool? == true) // or, if nullable, HasValue is true
&& (!(x is string s) || !string.IsNullOrEmpty(s)) // not an empty string
)
.ToList();
if (!distinctList.Any())
{
throw new ArgumentException("The orArgumentList must contain at least one valid value.", nameof(orArgumentList));
}
// build the SQL WHERE clause and parameter list
string sqlWhere = Environment.NewLine + clausePrefix + " " + columnReference + " IN ( ";
int listCount = distinctList.Count();
for (int i = 0; i < listCount; i++)
{
if (i > 0)
{
sqlWhere += ", ";
}
sqlWhere = sqlWhere + GetSetParameter(distinctList[i]);
}
sqlWhere += " ) ";
return sqlWhere + clausePostfix;
}
/// <summary>
/// Adds a string value to the ParameterList and returns '@parameterN' that is then appended to the SQL statement
/// i.e. @parameter1, @parameter2, etc.
/// </summary>
/// <param name="value">parameter string that is then appended to the SQL statement</param>
/// <param name="argument">parameter string that is then appended to the SQL statement</param>
/// <returns></returns>
private string GetSetParameter(object value)
private string GetSetParameter(object argument)
{
parameterCount++;
string parameterString = "@parameter" + parameterCount;
ParameterList.Add(parameterString, value);
ParameterList.Add(parameterString, argument);
return parameterString;
}
}

View File

@@ -317,6 +317,10 @@ namespace bnhtrade.Core.Logic.Inventory
});
}
/// <summary>
/// To be used internally (private). Deletes a stock journal entry and performs a consistency check, does not roll back transaction on fail.
/// </summary>
/// <returns>consistantcy check result, true=good, false=bad</returns>
private bool StockJournalDelete(IUnitOfWork uow, int stockJournalId)
{
// get journal entry
@@ -375,7 +379,6 @@ namespace bnhtrade.Core.Logic.Inventory
}
else
{
uow.Rollback();
return false;
}
}