Initial commit: JDE Scoping Tool migration project

Set up repository with legacy .NET Framework 4.8 source (OLD/),
new .NET 10 Blazor solution (NEW/), OpenSpec specifications,
documentation, and project configuration.
This commit is contained in:
Joseph Doherty
2026-01-02 07:43:29 -05:00
commit 26ff8d9b4f
1761 changed files with 596509 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Models;
using DDTek.Oracle;
namespace DataModel.Process
{
/// <summary>
/// MIS data loader for CMS interface
/// </summary>
public partial class CMS
{
/// <summary>
/// Fetches updates for MIS data
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for MIS data</returns>
public static IEnumerable<MisData> GetMisData(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<MisData>(queries["SQL_GET_MIS_DATA_FILTERED"], new { lastUpdateDT }, buffered: false, commandTimeout: 1200*50) :
connection.Query<MisData>(queries["SQL_GET_MIS_DATA"], buffered: false, commandTimeout: 1200*50);
foreach (var result in results)
{
if (result.ReleaseDate.HasValue)
{
result.ReleaseDate = result.ReleaseDate.Value.ToLocalTime();
}
yield return result;
}
}
}
}
}
+51
View File
@@ -0,0 +1,51 @@
using System;
using DDTek.Oracle;
using NLog;
namespace DataModel.Process
{
/// <summary>
/// CMS interface
/// </summary>
public partial class CMS
{
/// <summary>
/// Query repository name
/// </summary>
private const string RepositoryName = "CMS";
/// <summary>
/// Query repository instance
/// </summary>
private static readonly QueryRepository queries = new QueryRepository(RepositoryName, Config.CMSQueryRepo);
/// <summary>
/// Shared logger instance
/// </summary>
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
/// <summary>
/// Gets an open connection to the CMS DB
/// </summary>
/// <returns>Opened connection to the CMS DB</returns>
private static OracleConnection GetConnection()
{
OracleConnection connection;
try
{
//Create the connection to the database and open it
connection = new OracleConnection(Config.CMSCS);
connection.Open();
}
catch (Exception error)
{
//Log error and forward
logger.Error("GetConnection: failed to open connection to CMS: {0}.", error.Message);
throw new Exception("CMS: failed to open connection to CMS database.", error);
}
return connection;
}
}
}
+75
View File
@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// JDE business units tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updated branches
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last updated record already imported</param>
/// <returns>Streaming updated branches</returns>
public static IEnumerable<Branch> GetBranches(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<Branch>(queries["SQL_GET_BUSINESS_UNITS_FILTERED"], new { typeCode = "BP", dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<Branch>(queries["SQL_GET_BUSINESS_UNITS"], new { typeCode = "BP" }, buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
/// <summary>
/// Fetches updated profit centers
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last updated record already imported</param>
/// <returns>Streaming updated profit centers</returns>
public static IEnumerable<ProfitCenter> GetProfitCenters(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<ProfitCenter>(queries["SQL_GET_BUSINESS_UNITS_FILTERED"], new { typeCode = "I3", dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<ProfitCenter>(queries["SQL_GET_BUSINESS_UNITS"], new { typeCode = "I3" }, buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
/// <summary>
/// Fetches updated work centers
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last updated record already imported</param>
/// <returns>Streaming updated work centers</returns>
public static IEnumerable<WorkCenter> GetWorkCenters(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<WorkCenter>(queries["SQL_GET_BUSINESS_UNITS_FILTERED"], new { typeCode = "WC", dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<WorkCenter>(queries["SQL_GET_BUSINESS_UNITS"], new { typeCode = "WC" }, buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+32
View File
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// Function code tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for function codes
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for function codes</returns>
public static IEnumerable<FunctionCode> GetFunctionCodes(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = connection.Query<FunctionCode>(queries["SQL_GET_FUNCTION_CODES"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+35
View File
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// Item/part number tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for items (part numbers)
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for items (part numbers)</returns>
public static IEnumerable<Item> GetItems(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<Item>(queries["SQL_GET_ITEMS_FILTERED"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<Item>(queries["SQL_GET_ITEMS"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+35
View File
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// Lot location tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for lot locations
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for lot locations</returns>
public static IEnumerable<LotLocation> GetLotLocations(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<LotLocation>(queries["SQL_GET_LOT_LOCATIONS_FILTERED"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<LotLocation>(queries["SQL_GET_LOT_LOCATIONS"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+53
View File
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// Lot usage (CARDEX) tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for lot usages
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for lot usages</returns>
public static IEnumerable<LotUsage> GetLotUsages(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<LotUsage>(queries["SQL_GET_LOT_USAGES_FILTERED"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: 999999) :
connection.Query<LotUsage>(queries["SQL_GET_LOT_USAGES"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
/// <summary>
/// Fetches updates for lot usages archive
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for lot usages</returns>
public static IEnumerable<LotUsage> GetLotUsagesArchive(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = connection.Query<LotUsage>(queries["SQL_GET_LOT_USAGES_ARCHIVE"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+35
View File
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// Lot tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for lots
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for lots</returns>
public static IEnumerable<Lot> GetLots(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<Lot>(queries["SQL_GET_LOTS_FILTERED"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<Lot>(queries["SQL_GET_LOTS"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+35
View File
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// JDE organization hierarchy tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for organization hierarchy
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for organization hierarchy</returns>
public static IEnumerable<OrgHierarchy> GetOrgHierarchy(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<OrgHierarchy>(queries["SQL_GET_ORG_HIERARCHY_FILTERED"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<OrgHierarchy>(queries["SQL_GET_ORG_HIERARCHY"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+35
View File
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// Item master router tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for route masters
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming route masters</returns>
public static IEnumerable<RouteMaster> GetRouteMasters(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<RouteMaster>(queries["SQL_GET_ROUTE_MASTER_FILTERED"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<RouteMaster>(queries["SQL_GET_ROUTE_MASTER"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+36
View File
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
namespace DataModel.Process
{
/// <summary>
/// Status codes tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updated status codes
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last updated record already imported</param>
/// <returns>Streaming updated status codes</returns>
public static IEnumerable<StatusCode> GetStatusCodes(DateTime? lastUpdateDT = null)
{
using (DDTek.Oracle.OracleConnection connection = new DDTek.Oracle.OracleConnection(Config.GIWCS))
{
connection.Open();
var results = lastUpdateDT.HasValue ?
connection.Query<StatusCode>(queries["SQL_GET_STATUS_CODES_FILTERED"], new { dateUpdated = lastUpdateDT.Value.Date, timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<StatusCode>(queries["SQL_GET_STATUS_CODES"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+35
View File
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// User/operator tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for users
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for users</returns>
public static IEnumerable<JdeUser> GetUsers(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<JdeUser>(queries["SQL_GET_USERS"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<JdeUser>(queries["SQL_GET_USERS"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+53
View File
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// Work order component tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for workorder components
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for workorder components</returns>
public static IEnumerable<WorkOrderComponent> GetWorkOrderComponents(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<WorkOrderComponent>(queries["SQL_GET_WORKORDER_COMPONENTS_FILTERED"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<WorkOrderComponent>(queries["SQL_GET_WORKORDER_COMPONENTS"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
/// <summary>
/// Fetches updates for workorder components archive
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for workorder components</returns>
public static IEnumerable<WorkOrderComponent> GetWorkOrderComponentsArchive(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = connection.Query<WorkOrderComponent>(queries["SQL_GET_WORKORDER_COMPONENTS_ARCHIVE"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+45
View File
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// Work order routing transaction tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for work order routings
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming work order routings for lots</returns>
public static IEnumerable<WorkOrderRouting> GetWorkOrderRoutings(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<WorkOrderRouting>(queries["SQL_GET_WORKORDER_ROUTING_FILTERED"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<WorkOrderRouting>(queries["SQL_GET_WORKORDER_ROUTING"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
if (result.LastUpdateDT.Year < 1900 || result.LastUpdateDT.Year > 2500)
{
continue;
}
if (result.TransactionDate.Year < 1900 || result.TransactionDate.Year > 2500)
{
continue;
}
yield return result;
}
}
}
}
}
+53
View File
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// Work order job step tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for work order steps
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming work order steps for lots</returns>
public static IEnumerable<WorkOrderStep> GetWorkOrderSteps(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<WorkOrderStep>(queries["SQL_GET_WORKORDER_STEP_FILTERED"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<WorkOrderStep>(queries["SQL_GET_WORKORDER_STEP"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
/// <summary>
/// Fetches updates for work order steps archive
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming work order steps for lots</returns>
public static IEnumerable<WorkOrderStep> GetWorkOrderStepsArchive(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = connection.Query<WorkOrderStep>(queries["SQL_GET_WORKORDER_STEP_ARCHIVE"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+53
View File
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// Work order time tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for work order time transactions
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns></returns>
public static IEnumerable<WorkOrderTime> GetWorkOrderTimes(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<WorkOrderTime>(queries["SQL_GET_WORKORDER_TIMES_FILTERED"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<WorkOrderTime>(queries["SQL_GET_WORKORDER_TIMES"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
/// <summary>
/// Fetches updates for work order time transactions archive
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns></returns>
public static IEnumerable<WorkOrderTime> GetWorkOrderTimesArchive(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = connection.Query<WorkOrderTime>(queries["SQL_GET_WORKORDER_TIMES_ARCHIVE"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+53
View File
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// Work order tracking functionality for JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Fetches updates for work orders
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for work orders</returns>
public static IEnumerable<WorkOrder> GetWorkOrders(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = lastUpdateDT.HasValue ?
connection.Query<WorkOrder>(queries["SQL_GET_WORKORDERS_FILTERED"], new { dateUpdated = lastUpdateDT.Value.ToJDEDate(), timeUpdated = lastUpdateDT.Value.ToJDETime() }, buffered: false, commandTimeout: Config.QueryTimeout) :
connection.Query<WorkOrder>(queries["SQL_GET_WORKORDERS"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
/// <summary>
/// Fetches updates for work orders archive
/// </summary>
/// <param name="lastUpdateDT">Timestamp of last imported data</param>
/// <returns>Streaming updates for work orders</returns>
public static IEnumerable<WorkOrder> GetWorkOrdersArchive(DateTime? lastUpdateDT = null)
{
using (OracleConnection connection = GetConnection())
{
var results = connection.Query<WorkOrder>(queries["SQL_GET_WORKORDERS_ARCHIVE"], buffered: false, commandTimeout: Config.QueryTimeout);
foreach (var result in results)
{
yield return result;
}
}
}
}
}
+51
View File
@@ -0,0 +1,51 @@
using System;
using NLog;
using Oracle.ManagedDataAccess.Client;
namespace DataModel.Process
{
/// <summary>
/// JDE interface
/// </summary>
public partial class JDE
{
/// <summary>
/// Query repository name
/// </summary>
private const string RepositoryName = "JDE";
/// <summary>
/// Query repository instance
/// </summary>
private static readonly QueryRepository queries = new QueryRepository(RepositoryName, Config.JDEQueryRepo);
/// <summary>
/// Shared logger instance
/// </summary>
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
/// <summary>
/// Gets an open connection to the JDE DB
/// </summary>
/// <returns>Opened connection to the JDE DB</returns>
public static OracleConnection GetConnection()
{
OracleConnection connection;
try
{
//Create the connection to the database and open it
connection = new OracleConnection(Config.JDECS);
connection.Open();
}
catch (Exception error)
{
//Log error and forward
logger.Error("GetConnection: failed to open connection to JDE: {0}.", error.Message);
throw new Exception("JDE: failed to open connection to JDE database.", error);
}
return connection;
}
}
}
+103
View File
@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Dapper;
using DataModel.Models;
namespace DataModel.Process
{
/// <summary>
/// Item tracking functions for LotFinderDB interface
/// </summary>
public partial class LotFinderDB
{
/// <summary>
/// Query to find items with matching item number or description
/// </summary>
private const string SQL_SEARCH_ITEMS = @"
SELECT TOP 25
i.ShortItemNumber,
i.ItemNumber,
i.Description,
i.LastUpdateDT
FROM dbo.Item AS i
WHERE i.ItemNumber LIKE '%' + @filter + '%' OR
i.Description LIKE '%' + @filter + '%'
ORDER BY i.ItemNumber";
/// <summary>
/// Finds items with matching item number or description
/// </summary>
/// <param name="filter">Search filter</param>
/// <returns>Items with matching item number or description</returns>
public static List<Item> SearchItems(string filter)
{
List<Item> results = new List<Item>();
try
{
using (SqlConnection connection = GetConnection())
{
results.AddRange(connection.Query<Item>(SQL_SEARCH_ITEMS, new {filter}));
}
}
catch (Exception error)
{
//Log and forward exception
logger.Error("SearchItems: failed to search for item '{0}': {1}.", filter, error.Message);
throw new Exception($"Failed to get serach for item '{filter}' from LotFinderDB.", error);
}
return results;
}
/// <summary>
/// Query to find items with matching item numbers
/// </summary>
private const string SQL_LOOKUP_ITEMS = @"
SELECT i.ShortItemNumber,
i.ItemNumber,
i.Description,
i.LastUpdateDT
FROM dbo.Item AS i INNER JOIN
@itemNumbers AS i2 ON (i.ItemNumber = i2.ItemNumber)
ORDER BY i.ItemNumber";
/// <summary>
/// Finds items with matching item numbers
/// </summary>
/// <param name="itemNumbers">Item numbers to match</param>
/// <returns></returns>
public static List<Item> LookupItems(List<string> itemNumbers)
{
List<Item> results = new List<Item>();
try
{
//Create search filter parameter
DataTable dataTable = new DataTable();
dataTable.Columns.Add("ItemNumber", typeof(string));
foreach (string itemNumber in itemNumbers)
{
dataTable.Rows.Add(itemNumber);
}
using (SqlConnection connection = GetConnection())
{
results = connection.Query<Item>(SQL_LOOKUP_ITEMS, new { itemNumbers = dataTable.AsTableValuedParameter("ItemNumberFilterParameter") }).ToList();
}
}
catch (Exception error)
{
//Log and forward exception
logger.Error("LookupItems: failed to find matching items: {0}.", error.Message);
throw new Exception("LookupItems: failed to find matching items in LotFinderDB.", error);
}
return results;
}
}
}
+68
View File
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Dapper;
using DataModel.Models;
using DataModel.ViewModels;
namespace DataModel.Process
{
/// <summary>
/// Lot tracking functions for LotFinderDB interface
/// </summary>
public partial class LotFinderDB
{
/// <summary>
/// Query to find lots with matching lot numbers
/// </summary>
private const string SQL_LOOKUP_LOTS = @"
SELECT DISTINCT
l.LotNumber,
l.BranchCode,
l.ShortItemNumber,
l.ItemNumber,
l.SupplierCode,
l.LastUpdateDT
FROM dbo.Lot AS l INNER JOIN
@lotNumbers ln ON (l.LotNumber = ln.ComponentLotNumber AND
((l.ItemNumber IS NULL AND ln.ItemNumber IS NULL) OR l.ItemNumber = ln.ItemNumber))";
/// <summary>
/// Finds lots with matching lot numbers
/// </summary>
/// <param name="lots">Lot numbers to match</param>
/// <returns>List of matching lots</returns>
public static List<Lot> LookupLots(List<LotViewModel> lots)
{
List<Lot> results = new List<Lot>();
try
{
//Create search filter parameter
DataTable dataTable = new DataTable();
dataTable.Columns.Add("ComponentLotNumber", typeof(string));
dataTable.Columns.Add("ItemNumber", typeof(string));
foreach (LotViewModel lot in lots)
{
dataTable.Rows.Add(lot.LotNumber, lot.ItemNumber);
}
using (SqlConnection connection = GetConnection())
{
results = connection.Query<Lot>(SQL_LOOKUP_LOTS, new { lotNumbers = dataTable.AsTableValuedParameter("ComponentLotFilterParameter") }).ToList();
}
}
catch (Exception error)
{
//Log and forward exception
logger.Error("LookupLots: failed to find matching lots: {0}.", error.Message);
throw new Exception("LookupLots: failed to find matching lots in LotFinderDB.", error);
}
return results;
}
}
}
+67
View File
@@ -0,0 +1,67 @@
using System;
using System.Data.SqlClient;
using Dapper;
namespace DataModel.Process
{
/// <summary>
/// MIS data tracking functions for LotFinderDB interface
/// </summary>
public partial class LotFinderDB
{
/// <summary>
/// Post-processing script to set obsoletion dates
/// </summary>
private const string SQL_POSTPROCESS_MISDATA = @"
SET ANSI_WARNINGS OFF;
WITH cte AS (
SELECT md.MisNumber, md.RevID, md.Status, MIN(md.ReleaseDate) Released
FROM dbo.MisData AS md
GROUP BY md.MisNumber, md.RevID, md.Status
)
UPDATE dbo.MisData
SET ObsoleteDate = bl.Released
FROM cte bl
WHERE MisData.MisNumber = bl.MisNumber AND
MisData.RevID = bl.RevID AND
MisData.Status = 'Current' AND
bl.Status = 'BackLevel';
WITH cte AS (
SELECT md.MisNumber, md.RevID, md.Status, MIN(md.ReleaseDate) Released
FROM dbo.MisData AS md
GROUP BY md.MisNumber, md.RevID, md.Status
)
UPDATE dbo.MisData
SET ObsoleteDate = (SELECT TOP 1 nl.Released
FROM cte nl
WHERE MisData.MisNumber = nl.MisNumber AND
MisData.RevID < nl.RevID AND
MisData.Status = nl.Status
ORDER BY nl.RevID)
WHERE ObsoleteDate IS NULL;
ALTER INDEX [PK_MisData] ON [dbo].[MisData] REBUILD;";
/// <summary>
/// Performs post processing on imported Mis data
/// </summary>
public static void PostProcessMisData()
{
try
{
using (SqlConnection connection = GetConnection())
{
connection.Execute(SQL_POSTPROCESS_MISDATA);
}
}
catch (Exception error)
{
//Log and forward exception
logger.Error("PostProcessMisData: failed to post process MIS data: {0}.", error.Message);
throw new Exception($"Failed to post process MIS data from LotFinderDB.", error);
}
}
}
}
+100
View File
@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Dapper;
using DataModel.Models;
namespace DataModel.Process
{
/// <summary>
/// Profit center tracking functions for LotFinderDB interface
/// </summary>
public partial class LotFinderDB
{
/// <summary>
/// Query to find profit centers with matching code or description
/// </summary>
private const string SQL_SEARCH_PROFIT_CENTERS = @"
SELECT TOP 25
pc.Code,
pc.Description,
pc.LastUpdateDT
FROM dbo.ProfitCenter AS pc
WHERE pc.Code LIKE '%' + @filter + '%' OR
pc.Description LIKE '%' + @filter + '%'
ORDER BY pc.Code";
/// <summary>
/// Finds profit centers with matching code or description
/// </summary>
/// <param name="filter">Search filter</param>
/// <returns>Profit centers with matching code or description</returns>
public static List<ProfitCenter> SearchProfitCenters(string filter)
{
List<ProfitCenter> results = new List<ProfitCenter>();
try
{
using (SqlConnection connection = GetConnection())
{
results.AddRange(connection.Query<ProfitCenter>(SQL_SEARCH_PROFIT_CENTERS, new { filter }));
}
}
catch (Exception error)
{
//Log and forward exception
logger.Error("SearchProfitCenters: failed to search for profit centers '{0}': {1}.", filter, error.Message);
throw new Exception($"Failed to search for profit centers '{filter}' from LotFinderDB.", error);
}
return results;
}
/// <summary>
/// Query to find profit centers with matching profit center codes
/// </summary>
private const string SQL_LOOKUP_PROFIT_CENTERS = @"
SELECT pc.Code,
pc.Description,
pc.LastUpdateDT
FROM dbo.ProfitCenter AS pc INNER JOIN
@profitCenterCodes AS pc2 ON (pc.Code = pc2.Code)
ORDER BY pc.Code";
/// <summary>
/// Finds profit centers with matching profit center codes
/// </summary>
/// <param name="profitCenterCodes">Profit center codes to match</param>
/// <returns>List of matching profit centers</returns>
public static List<ProfitCenter> LookupProfitCenters(List<string> profitCenterCodes)
{
List<ProfitCenter> results = new List<ProfitCenter>();
try
{
//Create search filter parameter
DataTable dataTable = new DataTable();
dataTable.Columns.Add("Code", typeof(string));
foreach (string profitCenter in profitCenterCodes)
{
dataTable.Rows.Add(profitCenter);
}
using (SqlConnection connection = GetConnection())
{
results = connection.Query<ProfitCenter>(SQL_LOOKUP_PROFIT_CENTERS, new { profitCenterCodes = dataTable.AsTableValuedParameter("ProfitCenterFilterParameter") }).ToList();
}
}
catch (Exception error)
{
//Log and forward exception
logger.Error("LookupProfitCenters: failed to find matching profit centers: {0}.", error.Message);
throw new Exception("LookupProfitCenters: failed to find matching profit centers in LotFinderDB.", error);
}
return results;
}
}
}
+219
View File
@@ -0,0 +1,219 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Dapper;
using DataModel.Helpers;
using DataModel.Models;
using Newtonsoft.Json;
namespace DataModel.Process
{
/// <summary>
/// Search management functionality of LotFinderDB interface
/// </summary>
public partial class LotFinderDB
{
/// <summary>
/// Query to get user's searches
/// </summary>
private const string SQL_GET_USER_SEARCHES = @"
SELECT s.ID,
s.Name,
s.Status,
s.SubmitDT,
s.StartDT,
s.EndDT
FROM dbo.Search s
WHERE s.UserName = @userName
ORDER BY s.SubmitDT";
/// <summary>
/// Gets user's searches
/// </summary>
/// <param name="userName">User name to match</param>
/// <returns>List of user's searches</returns>
public static List<Search> GetUserSearches(string userName)
{
List<Search> results = new List<Search>();
try
{
using (SqlConnection connection = GetConnection())
{
results.AddRange(connection.Query<Search>(SQL_GET_USER_SEARCHES, new {userName}));
}
}
catch (Exception error)
{
//Log but do not forward error
logger.Error("GetUserSearches: failed to get searches for user '{0}': {1}.", userName, error.Message);
}
return results;
}
/// <summary>
/// Query to get queued searches
/// </summary>
private const string SQL_GET_QUEUED_SEARCHES = @"
SELECT s.ID,
s.UserName,
s.Name,
s.Status,
s.SubmitDT,
s.StartDT,
s.EndDT
FROM dbo.Search s
WHERE s.Status < 3
ORDER BY s.SubmitDT";
/// <summary>
/// Gets queued searches
/// </summary>
/// <returns>List of searches that have been submitted but not completed</returns>
public static List<Search> GetQueuedSearches()
{
List<Search> results = new List<Search>();
try
{
using (SqlConnection connection = GetConnection())
{
results.AddRange(connection.Query<Search>(SQL_GET_QUEUED_SEARCHES));
}
}
catch (Exception error)
{
//Log but do not forward error
logger.Error("GetQueuedSearches: failed to get queued searches: {0}.", error.Message);
}
return results;
}
/// <summary>
/// Query to get search with matching ID
/// </summary>
private const string SQL_GET_SEARCH = @"
SELECT s.UserName,
s.Name,
s.Status,
s.SubmitDT,
s.StartDT,
s.EndDT,
s.Criteria as CriteriaJSON
FROM dbo.Search s
WHERE s.ID = @id";
/// <summary>
/// Gets the search with matching ID
/// </summary>
/// <param name="id">Search ID to match</param>
/// <returns>Search with matching ID</returns>
public static Search GetSearch(int id)
{
Search result = null;
try
{
using (SqlConnection connection = GetConnection())
{
result = connection.QueryFirstOrDefault<Search>(SQL_GET_SEARCH, new {id});
if (result != null && !string.IsNullOrEmpty(result.CriteriaJSON))
{
result.ID = id;
result.Criteria = JsonConvert.DeserializeObject<SearchCriteria>(result.CriteriaJSON);
}
}
}
catch (Exception error)
{
//Log but do not forward error
logger.Error("GetSearch: failed to get search with ID '{0}': {1}.", id, error.Message);
}
return result;
}
/// <summary>
/// Query to get the saved results for the search with matching ID
/// </summary>
private const string SQL_GET_SEARCH_RESULTS = @"
SELECT s.Results
FROM dbo.Search AS s
WHERE s.ID = @id";
/// <summary>
/// Gets the saved results for the search with matching ID
/// </summary>
/// <param name="id">Search ID to match</param>
/// <returns>Raw data for saved search results</returns>
public static byte[] GetSearchResults(int id)
{
byte[] result = null;
try
{
using (SqlConnection connection = GetConnection())
{
result = connection.Query<byte[]>(SQL_GET_SEARCH_RESULTS, new {id}).FirstOrDefault();
}
}
catch (Exception error)
{
//Log but do not forward error
logger.Error("GetSearchResults: failed to get results for search with ID '{0}': {1}.", id, error.Message);
}
return result;
}
/// <summary>
/// Saves the search to the database
/// </summary>
/// <param name="search">Search to submit</param>
/// <returns>PK ID of search record generated</returns>
public static int SubmitSearch(Search search)
{
int searchID = -1;
try
{
search.Status = SearchStatus.Submitted;
search.SubmitDT = DateTime.Now;
using (SqlConnection connection = GetConnection())
{
using (SqlCommand command = new SqlCommand("SubmitSearch", connection))
{
command.CommandType = CommandType.StoredProcedure;
//Bind parameters
command.Bind("p_UserName", search.UserName);
command.Bind("p_Name", search.Name);
command.Bind("p_Criteria", search.Criteria.ToJSON());
SqlParameter searchIDParameter = new SqlParameter("o_SearchID", SqlDbType.Int)
{
Direction = ParameterDirection.Output
};
command.Parameters.Add(searchIDParameter);
//Execute procedure and extract values
command.ExecuteNonQuery();
searchID = Convert.ToInt32(searchIDParameter.Value);
}
}
}
catch (Exception error)
{
//Log but do not forward error
logger.Error("SubmitSearch: failed to get submit search: {0}.", error.Message);
}
return searchID;
}
}
}
+103
View File
@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Dapper;
using DataModel.Models;
namespace DataModel.Process
{
/// <summary>
/// User tracking functions for LotFinderDB interface
/// </summary>
public partial class LotFinderDB
{
/// <summary>
/// Finds users with matching user ID or full name
/// </summary>
private const string SQL_SEARCH_USERS = @"
SELECT TOP 25
u.AddressNumber,
COALESCE(u.UserID,' ') AS UserID,
u.FullName,
u.LastUpdateDT
FROM dbo.JdeUser AS u
WHERE u.UserID LIKE '%' + @filter + '%' OR
u.FullName LIKE '%' + @filter + '%' OR
CAST(u.AddressNumber AS VARCHAR(10)) LIKE '%' + @filter + '%'
ORDER BY u.UserID, u.FullName";
/// <summary>
/// Finds users with matching user ID or full name
/// </summary>
/// <param name="filter">Search filter</param>
/// <returns>Users with matching matching user ID or full name</returns>
public static List<JdeUser> SearchUsers(string filter)
{
List<JdeUser> results = new List<JdeUser>();
try
{
using (SqlConnection connection = GetConnection())
{
results.AddRange(connection.Query<JdeUser>(SQL_SEARCH_USERS, new{filter}));
}
}
catch (Exception error)
{
//Log and forward exception
logger.Error("SearchUsers: failed to search for user '{0}': {1}.", filter, error.Message);
throw new Exception($"Failed to get serach for user '{filter}' from LotFinderDB.", error);
}
return results;
}
/// <summary>
/// Query to find users with matching user IDs
/// </summary>
private const string SQL_LOOKUP_USERS = @"
SELECT u.AddressNumber,
u.UserID,
u.FullName,
u.LastUpdateDT
FROM dbo.JdeUser AS u INNER JOIN
@userIDs u2 ON (u.UserID = u2.UserName OR CAST(u.AddressNumber AS VARCHAR(20)) = u2.UserName)
ORDER BY u.UserID";
/// <summary>
/// Finds users with matching user IDs
/// </summary>
/// <param name="userIDs">User IDs to match</param>
/// <returns>Users with matching user IDs</returns>
public static List<JdeUser> LookupUsers(List<string> userIDs)
{
List<JdeUser> results = new List<JdeUser>();
try
{
//Create search filter parameter
DataTable dataTable = new DataTable();
dataTable.Columns.Add("UserName", typeof(string));
foreach (string userID in userIDs)
{
dataTable.Rows.Add(userID);
}
using (SqlConnection connection = GetConnection())
{
results = connection.Query<JdeUser>(SQL_LOOKUP_USERS, new { userIDs = dataTable.AsTableValuedParameter("OperatorFilterParameter") }).ToList();
}
}
catch (Exception error)
{
//Log and forward exception
logger.Error("LookupUsers: failed to find matching users: {0}.", error.Message);
throw new Exception("LookupUsers: failed to find matching users in LotFinderDB.", error);
}
return results;
}
}
}
+100
View File
@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Dapper;
using DataModel.Models;
namespace DataModel.Process
{
/// <summary>
/// Work center tracking functions for LotFinderDB interface
/// </summary>
public partial class LotFinderDB
{
/// <summary>
/// Query to find profit centers with matching code or description
/// </summary>
private const string SQL_SEARCH_WORK_CENTERS = @"
SELECT TOP 25
wc.Code,
wc.Description,
wc.LastUpdateDT
FROM dbo.WorkCenter AS wc
WHERE wc.Code LIKE '%' + @filter + '%' OR
wc.Description LIKE '%' + @filter + '%'
ORDER BY wc.Code";
/// <summary>
/// Finds work centers with matching code or description
/// </summary>
/// <param name="filter">Search filter</param>
/// <returns>Work centers with matching code or description</returns>
public static List<WorkCenter> SearchWorkCenters(string filter)
{
List<WorkCenter> results = new List<WorkCenter>();
try
{
using (SqlConnection connection = GetConnection())
{
results.AddRange(connection.Query<WorkCenter>(SQL_SEARCH_WORK_CENTERS, new { filter }));
}
}
catch (Exception error)
{
//Log and forward exception
logger.Error("SearchWorkCenters: failed to search for work centers '{0}': {1}.", filter, error.Message);
throw new Exception($"Failed to search for work centers '{filter}' from LotFinderDB.", error);
}
return results;
}
/// <summary>
/// Query to find work orders with matching work order numbers
/// </summary>
private const string SQL_LOOKUP_WORK_CENTERS = @"
SELECT wc.Code,
wc.Description,
wc.LastUpdateDT
FROM dbo.WorkCenter AS wc INNER JOIN
@workCenterCodes wc2 ON (wc.Code = wc2.Code)
ORDER BY wc.Code";
/// <summary>
/// Finds work centers with matching work center codes
/// </summary>
/// <param name="workCenterCodes">Work center codes to match</param>
/// <returns>List of matching work centers</returns>
public static List<WorkCenter> LookupWorkCenters(List<string> workCenterCodes)
{
List<WorkCenter> results = new List<WorkCenter>();
try
{
//Create search filter parameter
DataTable dataTable = new DataTable();
dataTable.Columns.Add("Code", typeof(string));
foreach (string workCenter in workCenterCodes)
{
dataTable.Rows.Add(workCenter);
}
using (SqlConnection connection = GetConnection())
{
results = connection.Query<WorkCenter>(SQL_LOOKUP_WORK_CENTERS, new { workCenterCodes = dataTable.AsTableValuedParameter("WorkCenterFilterParameter") }).ToList();
}
}
catch (Exception error)
{
//Log and forward exception
logger.Error("LookupWorkCenters: failed to find matching work centers: {0}.", error.Message);
throw new Exception("LookupWorkCenters: failed to find matching work centers in LotFinderDB.", error);
}
return results;
}
}
}
+58
View File
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Dapper;
using DataModel.Models;
namespace DataModel.Process
{
/// <summary>
/// Workorder tracking functions for LotFinderDB interface
/// </summary>
public partial class LotFinderDB
{
/// <summary>
/// Query to find work orders with matching work order numbers
/// </summary>
private const string SQL_LOOKUP_WORKORDERS = @"
SELECT *
FROM dbo.WorkOrder AS wo INNER JOIN
@workOrderNumbers wo2 ON (wo.WorkOrderNumber = wo2.WorkOrderNumber)";
/// <summary>
/// Finds work orders with matching work order numbers
/// </summary>
/// <param name="workorderNumbers">Workorder numbers to match</param>
/// <returns>List of matching workorders</returns>
public static List<WorkOrder> LookupWorkorders(List<long> workorderNumbers)
{
List<WorkOrder> results = new List<WorkOrder>();
try
{
//Create search filter parameter
DataTable dataTable = new DataTable();
dataTable.Columns.Add("WorkOrderNumber", typeof(long));
foreach (long workOrderNumber in workorderNumbers)
{
dataTable.Rows.Add(workOrderNumber);
}
using (SqlConnection connection = GetConnection())
{
results = connection.Query<WorkOrder>(SQL_LOOKUP_WORKORDERS, new { workOrderNumbers = dataTable.AsTableValuedParameter("WorkOrderFilterParameter") }).ToList();
}
}
catch (Exception error)
{
//Log and forward exception
logger.Error("LookupWorkorders: failed to find matching workorders: {0}.", error.Message);
throw new Exception("LookupWorkorders: failed to find matching workorders in LotFinderDB.", error);
}
return results;
}
}
}
+151
View File
@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Dapper;
using DataModel.Models;
using NLog;
namespace DataModel.Process
{
/// <summary>
/// LotFinder cache database interface
/// </summary>
public partial class LotFinderDB
{
/// <summary>
/// Default command timeout (ms)
/// </summary>
protected const int DEFAULT_TIMEOUT = 600;
/// <summary>
/// Shared logger instance
/// </summary>
protected static readonly Logger logger = LogManager.GetCurrentClassLogger();
/// <summary>
/// Gets opened connection to LotFinder database
/// </summary>
/// <returns>Open SqlConnection to LotFinder database</returns>
public static SqlConnection GetConnection()
{
SqlConnection connection = null;
try
{
//Create and open connection to LotFinder database
connection = new SqlConnection(Config.LotFinderDBCS);
connection.Open();
}
catch (Exception error)
{
//Log error and forward
logger.Error("GetConnection: failed to open connection to DB: {0}.", error.Message);
throw new Exception("LotFinderDB: failed to open connection to database.", error);
}
return connection;
}
/// <summary>
/// SQL to rebuild all indices on table with fillfactor of 95
/// </summary>
private const string SQL_REBUILD_INDICES = "ALTER INDEX ALL ON {0} REBUILD WITH (FILLFACTOR = 95);";
/// <summary>
/// Rebuilds all the indices on the given table with fillfactor of 95
/// </summary>
/// <param name="tableName">Name of table to rebuild indices on</param>
public static void RebuildIndices(string tableName)
{
using (SqlConnection connection = GetConnection())
{
connection.Execute(string.Format(SQL_REBUILD_INDICES, tableName), commandTimeout: DEFAULT_TIMEOUT);
}
}
/// <summary>
/// Generates table-valued parameter data table
/// </summary>
/// <typeparam name="T">Key data type</typeparam>
/// <param name="keys">Keys to store in table</param>
/// <returns>Populated table-value parameter data table</returns>
public static DataTable GenerateTableParameter<T>(List<T> keys)
{
DataTable dataTable = new DataTable();
dataTable.Columns.Add("Key", typeof(T));
foreach (T key in keys)
{
dataTable.Rows.Add(key);
}
return dataTable;
}
private const string SQL_GET_LAST_DATA_UPDATES = @"
WITH DU_CTE AS (
SELECT du.*,
ROW_NUMBER() OVER (PARTITION BY du.TableName, du.UpdateType ORDER BY du.StartDT DESC) RN
FROM dbo.DataUpdate AS du
)
SELECT cte.SourceSystem,
cte.SourceData,
cte.TableName,
cte.StartDT,
cte.EndDT,
cte.UpdateType,
cte.WasSuccessful,
cte.NumberRecords
FROM DU_CTE cte
WHERE cte.RN = 1";
public static List<DataUpdate> GetLastDataUpdates()
{
List<DataUpdate> dataUpdates = new List<DataUpdate>();
using (SqlConnection connection = GetConnection())
{
dataUpdates.AddRange(connection.Query<DataUpdate>(SQL_GET_LAST_DATA_UPDATES));
}
return dataUpdates;
}
private const string SQL_GET_TABLE_COLUMNS = @"
SELECT c.name AS Name,
CASE t2.name
WHEN 'varchar' THEN 'VARCHAR(' + CAST(c.max_length AS VARCHAR(10)) + ')'
WHEN 'decimal' THEN 'DECIMAL(' + CAST(c.precision AS VARCHAR(4)) + ',' + CAST(c.scale AS VARCHAR(4)) + ')'
ELSE UPPER(t2.name)
END AS Definition
FROM sys.columns c INNER JOIN
sys.types AS t2 ON (c.system_type_id = t2.system_type_id) INNER JOIN
sys.tables t ON (c.object_id = t.object_id)
WHERE t.name = @name
ORDER BY c.column_id";
private const string SQL_GET_TABLE_PRIMARY_KEY = @"
SELECT COLUMN_NAME AS Name
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(CONSTRAINT_SCHEMA + '.' + QUOTENAME(CONSTRAINT_NAME)), 'IsPrimaryKey') = 1 AND
TABLE_NAME = @name
ORDER BY ORDINAL_POSITION";
public static TableSpec GetTableSpec(string name)
{
TableSpec tableSpec = new TableSpec() { Name = name };
using (SqlConnection connection = GetConnection())
{
//Load columns
tableSpec.Columns.AddRange(connection.Query<ColumnSpec>(SQL_GET_TABLE_COLUMNS, new { name }));
//Load primary key
tableSpec.PrimaryKey.AddRange(connection.Query<string>(SQL_GET_TABLE_PRIMARY_KEY, new { name }).Select(cn => tableSpec.GetColumn(cn)));
}
return tableSpec;
}
}
}
+108
View File
@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.IO;
using NLog;
namespace DataModel.Process
{
public class QueryRepository
{
/// <summary>
/// Repository name
/// </summary>
public string Name { get; }
/// <summary>
/// Repository base directory
/// </summary>
public string BaseDirectory { get; }
/// <summary>
/// In memory cache
/// </summary>
private static readonly Dictionary<string, string> cache = new Dictionary<string, string>();
/// <summary>
/// Shared logger instance
/// </summary>
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Repository name</param>
/// <param name="baseDirectory">Repository base directory</param>
public QueryRepository(string name, string baseDirectory)
{
Name = name;
BaseDirectory = baseDirectory;
if (!Directory.Exists(baseDirectory))
{
Directory.CreateDirectory(baseDirectory);
}
logger.Info($"Query repository '{name}' initialized at base directory '{baseDirectory}'.");
}
/// <summary>
/// Gets query SQL
/// </summary>
/// <param name="queryName">Name of query to get SQL for</param>
/// <returns>Query SQL</returns>
public string GetQuery(string queryName)
{
string querySource = string.Empty;
if (!cache.TryGetValue(queryName, out querySource))
{
//Check if file exists
string fullPath = Path.Combine(BaseDirectory, $"{queryName}.sql");
if (!File.Exists(fullPath))
{
throw new Exception($"Cannot retreive query '{queryName}': '{fullPath}' does not exist");
}
//Read file
querySource = File.ReadAllText(fullPath);
querySource = querySource.Replace("PRODDTA", "PRODDTA");
querySource = querySource.Replace("ARCDTAPD", "ARCDTAPD");
File.WriteAllText(fullPath, querySource);
//Cache source
cache.Add(queryName, querySource);
}
return querySource;
}
/// <summary>
/// Sets querie's SQL
/// </summary>
/// <param name="queryName">Name of query to set SQL for</param>
/// <param name="querySource">SQL to set for query</param>
public void SetQuery(string queryName, string querySource)
{
logger.Info($"[{Name}] setting SQL for query '{queryName}'.");
//Update cache
cache[queryName] = querySource;
//Write source to file
string fullPath = Path.Combine(BaseDirectory, $"{queryName}.sql");
File.WriteAllText(fullPath, querySource);
}
/// <summary>
/// Indexer override
/// </summary>
/// <param name="queryName">Name of query</param>
/// <returns>SQL for query</returns>
public string this[string queryName]
{
get => GetQuery(queryName);
set => SetQuery(queryName, value);
}
}
}