Can I use SQLParameter when having a variable quantity of fields to update? - ado.net

I have a table with eighty fields, none to seventy of them can change depending of an update process I have. For example:
if (process.result == 1)
cmd.CommandText = "UPDATE T SET f1=1, f6='S'" ;
else if (Process.result == 2)
cmd.CommandText = string.Format("UPDATE T SET f1=2, f12={0},f70='{1}'", getData(), st);
else if ..... etc.
I can optimize the building process of the UPDATE statement, however I would like to use SQLParameter; is that possible and convenient given the variablity of data to update?
Thanks.

For each if statement you currently are using inline string formats, you could just as well just add the sql params instead.
The formatting of the UPDATE string could be replaced with the selected sql params you require to be updated insted.

Related

How to fix FirstOrDefault returning Null in Linq

My Linq Query keeps returning the null error on FirstOrDefault
The cast to value type 'System.Int32' failed because the materialized value is null
because it can't find any records to match on the ClinicalAssetID form the ClinicalReading Table, fair enough!
But I want the fields in my details page just to appear blank if the table does not have matching entry.
But how can I handle the null issue when using the order by function ?
Current Code:
var ClinicalASSPATINCVM = (from s in db.ClinicalAssets
join cp in db.ClinicalPATs on s.ClinicalAssetID equals cp.ClinicalAssetID into AP
from subASSPAT in AP.DefaultIfEmpty()
join ci in db.ClinicalINSs on s.ClinicalAssetID equals ci.ClinicalAssetID into AI
from subASSINC in AI.DefaultIfEmpty()
join co in db.ClinicalReadings on s.ClinicalAssetID equals co.ClinicalAssetID into AR
let subASSRED = AR.OrderByDescending(subASSRED => subASSRED.MeterReadingDone).FirstOrDefault()
select new ClinicalASSPATINCVM
{
ClinicalAssetID = s.ClinicalAssetID,
AssetTypeName = s.AssetTypeName,
ProductName = s.ProductName,
ModelName = s.ModelName,
SupplierName = s.SupplierName,
ManufacturerName = s.ManufacturerName,
SerialNo = s.SerialNo,
PurchaseDate = s.PurchaseDate,
PoNo = s.PoNo,
Costing = s.Costing,
TeamName = s.TeamName,
StaffName = s.StaffName,
WarrantyEndDate = subASSPAT.WarrantyEndDate,
InspectionDate = subASSPAT.InspectionDate,
InspectionOutcomeResult = subASSPAT.InspectionOutcomeResult,
InspectionDocumnets = subASSPAT.InspectionDocumnets,
LastTypeofInspection = subASSINC.LastTypeofInspection,
NextInspectionDate = subASSINC.NextInspectionDate,
NextInspectionType = subASSINC.NextInspectionType,
MeterReadingDone = subASSRED.MeterReadingDone,
MeterReadingDue = subASSRED.MeterReadingDue,
MeterReading = subASSRED.MeterReading,
MeterUnitsUsed = subASSRED.MeterUnitsUsed,
FilterReplaced = subASSRED.FilterReplaced
}).FirstOrDefault(x => x.ClinicalAssetID == id);
Tried this but doesn't work
.DefaultIfEmpty(new ClinicalASSPATINCVM())
.FirstOrDefault()
Error was:
CS1929 'IOrderedEnumerable<ClinicalReading>' does not contain a definition for 'DefaultIfEmpty' and the best extension method overload 'Queryable.DefaultIfEmpty<ClinicalASSPATINCVM>(IQueryable<ClinicalASSPATINCVM>, ClinicalASSPATINCVM)' requires a receiver of type 'IQueryable<ClinicalASSPATINCVM>'
Feel a little closer with this but still errors
let subASSRED = AR.OrderByDescending(subASSRED => (subASSRED.MeterReadingDone != null) ? subASSRED.MeterReadingDone : String.Empty).FirstOrDefault()
Error:
CS0173 Type of conditional expression cannot be determined because there is no implicit conversion between 'System.DateTime?' and 'string'
The original error means that some of the following properties of the ClinicalASSPATINCVM class - MeterReadingDone, MeterReadingDue, MeterReading, MeterUnitsUsed, or FilterReplaced is of type int.
Remember that subASSRED here
let subASSRED = AR.OrderByDescending(subASSRED => subASSRED.MeterReadingDone).FirstOrDefault()
might be null (no corresponding record).
Now look at this part of the projection:
MeterReadingDone = subASSRED.MeterReadingDone,
MeterReadingDue = subASSRED.MeterReadingDue,
MeterReading = subASSRED.MeterReading,
MeterUnitsUsed = subASSRED.MeterUnitsUsed,
FilterReplaced = subASSRED.FilterReplaced
If that was LINQ to Objects, all these would generate NRE (Null Reference Exception) at runtime. In LINQ to Entities this is converted and executed as SQL. SQL has no issues with expression like subASSRED.SomeProperty because SQL supports NULL naturally even if SomeProperty normally does not allow NULL. So the SQL query executes normally, but now EF must materialize the result into objects, and the C# object property is not nullable, hence the error in question.
To solve it, find the int property(es) and use the following pattern inside query:
SomeIntProperty = (int?)subASSRED.SomeIntProperty ?? 0 // or other meaningful default
or change receiving object property type to int? and leave the original query as is.
Do the same for any non nullable type property, e.g. DateTime, double, decimal, Guid etc.
You're problem is because your DefaultIfEmpty is executed AsQueryable. Perform it AsEnumerable and it will work:
// create the default element only once!
static readonly ClinicalAssPatInVcm defaultElement = new ClinicalAssPatInVcm ();
var result = <my big linq query>
.Where(x => x.ClinicalAssetID == id)
.AsEnumerable()
.DefaultIfEmpty(defaultElement)
.FirstOrDefault();
This won't lead to a performance penalty!
Database management systems are extremely optimized for selecting data. One of the slower parts of a database query is the transport of the selected data to your local process. Hence it is wise to let the DBMS do most of the selecting, and only after you know that you only have the data that you really plan to use, move the data to your local process.
In your case, you need at utmost one element from your DBMS, and if there is nothing, you want to use a default object instead.
AsQueryable will move the selected data to your local process in a smart way, probably per "page" of selected data.
The page size is a good compromise: not too small, so you don't have to ask for the next page too often; not too large, so that you don't transfer much more items than you actually use.
Besides, because of the Where statement you expect at utmost one element anyway. So that a full "page" is fetched is no problem, the page will contain only one element.
After the page is fetched, DefaultIfEmpty checks if the page is empty, and if so, returns a sequence containing the defaultElement. If not, it returns the complete page.
After the DefaultIfEmpty you only take the first element, which is what you want.

Entity Framework Core, Stored Procedure

I am totally confused regarding how to use Stored Procedures using Entity Framework Core. If the stored procedure return an anonymous type, how do I retrieve the data? If the return type is not anonymous, what should I do? How do I add input/output parameters?
I am asking these questions because everywhere I look, I get a different answer. I guess EF Core is evolving rapidly and Microsoft is dabbling with a lot of ideas.
How do I add input/output parameters?
I'm going to answer this particular question of yours.
Below is a TSQL stored procedure with two input and two output parameters
CREATE PROCEDURE [dbo].[yourstoredprocedure]
-- Add the parameters for the stored procedure here
#varone bigint
,#vartwo Date
,#varthree double precision OUTPUT
,#varfour bigint OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- YOUR CODE HERE
SET #varthree = 10.02;
SET #varfour = #varone;
return;
END
Now To execute this stored procedure using Entity Framework Core
MyContext.Database
.ExecuteSqlCommand(#"EXECUTE [yourstoredprocedure] " +
" {0} " +
", {1} " +
",#varthree OUTPUT " +
", #varfour OUTPUT ", dataOne, dataTwo, outputVarOne, outputVarTwo);
var outputResultOne= outputVarOne.Value as double?;
var outputResultTwo= outputVarTwo.Value as long?;
You can pass your input simply using parameterized query as above. You can also create named parameters. such as for output parameters, I've created two named parameters as -
var outputVarOne = new SqlParameter
{
ParameterName = "#varthree ",
DbType = System.Data.DbType.Double,
Direction = System.Data.ParameterDirection.Output
};
var outputVarTwo = new SqlParameter
{
ParameterName = "#varfour ",
DbType = System.Data.DbType.Int64,
Direction = System.Data.ParameterDirection.Output
};
And This is how using EF Core you execute a stored procedure with input and output parameters. Hope this helps someone.
This solution provides methods that call a stored procedure and maps the returned value to a defined (non-model) entity. https://github.com/verdie-g/StoredProcedureDotNetCore
Microsoft address this issue:
"SQL queries can only be used to return entity types that are part of your model. There is an enhancement on our backlog to enable returning ad-hoc types from raw SQL queries." https://learn.microsoft.com/en-us/ef/core/querying/raw-sql
And here is the issue tracked in GitHub: https://github.com/aspnet/EntityFramework/issues/1862
you might use an extention like StoredProcedureEFCore
Then the usage is more intuitively.
List rows = null;
ctx.LoadStoredProc("dbo.ListAll")
.AddParam("limit", 300L)
.AddParam("limitOut", out IOutParam<long> limitOut)
.Exec(r => rows = r.ToList<Model>());
long limitOutValue = limitOut.Value;
ctx.LoadStoredProc("dbo.ReturnBoolean")
.AddParam("boolean_to_return", true)
.ReturnValue(out IOutParam<bool> retParam)
.ExecNonQuery();
bool b = retParam.Value;
ctx.LoadStoredProc("dbo.ListAll")
.AddParam("limit", 1L)
.ExecScalar(out long l);

VB Script in Access Variable not found

So I was advised that I could create some copy replace functionality to this form.
Here is my coding attempt in VB:
First I connect to DB using DAO. Then I use a SELECT statement that has been verified to pull the last record inserted into the DB. Then I try to refill the controls with the values from the query but I am getting reference errors.
Private Sub AutoFill_Click()
Dim db As DAO.Database, rs As DAO.Recordset
Dim strSQL As String
Set db = CurrentDb()
strSQL = "SELECT DISTINCTROW TOP 1 CPOrders.Cust, Customer.NAME, CPOrders.CP_Ref, CPOrders.Slsman, CPOrders.Date_opn, CPOrders.CPSmall, CPOrders.InvIssu, CPOrders.InvNo, CPOrders.InvDate, CPOrders.DueDate, CPOrders.ETADate, CPOrders.Closed, CPOrders.BuyerRef, CPOrders.ToCity, CPOrders.ToState, CPOrders.ToCtry, CPOrders.ToPort, CPOrders.Supplier, CPOrders.Origin, CPOrders.Product, CPOrders.GradeType, CPOrders.NoUnits, CPOrders.Pkg, CPOrders.Qty, CPOrders.TotSale, CPOrders.TotCost, CPOrders.GrMargin, CPOrders.[Sale$/Unit], CPOrders.[Cost$/Unit], CPOrders.OceanCost, CPOrders.OceanNotes, CPOrders.BLadingDate, CPOrders.USAPort, CPOrders.FOBCost, CPOrders.FASExportVal, CPOrders.InlandFrt, CPOrders.CommodCode, CPOrders.Notes FROM Customer INNER JOIN CPOrders ON Customer.[CUST_#] = CPOrders.Cust ORDER BY CPOrders.CP_Ref desc;"
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset, dbReadOnly)
rs.MoveFirst
CP_Ref.ControlSource = rs!CP_Ref
Slsman.ControlSource = rs!Slsman
CPSmall.ControlSource = rs!CPSmall
InvIssu.ControlSource = rs!InvIssu
InvDate.ControlSource = rs!InvDate
DueDate.ControlSource = rs!DueDate
Closed.ControlSource = rs!Closed
rs.Close
db.Close
The control source reference picks up and autocompletes the word.
I would think that as it stands. although i'm not filling all the values with records from my SELECT statement that it would populate but instead i get things like #NAME? where the values should be. I also get a break in my code and it says "Invalid use of null"
Why? I appreciate your guys input and I can provider screenshots if necessary. I think this is involving the reference tie, but I'm not sure. Any help is much appreciated.
You are using the field names from the SELECT statement as if they were variables.
CP_Ref.ControlSource = rs("CP_Ref")
Slsman.ControlSource = rs("Slsman")
CPSmall.ControlSource = rs("CPSmall")
InvIssu.ControlSource = rs("InvIssu")
InvDate.ControlSource = rs("InvDate")
DueDate.ControlSource = rs("DueDate")
Closed.ControlSource = rs("Closed")
When you have that worked out, tackle the "Invalid use of null" problem by first identifying any fields that could potentially be NULL and using something like
SELECT Iif(IsNull([InvDate]), '', [InvDate]) As [InvDate], ...
in the SELECT statement to pass across a minimum of an empty string rather than a NULL value.

What does this string of code: gr.sys_id[key] = current.getValue(glideElement.getName());

I'm trying to copy (duplicate) a record in ServiceNow table of incidents, but can not make this string work: gr.sys_id[key] = current.getValue(glideElement.getName());
The goal is to copy all fields values except sys_id.
Take a look at the UI Action Insert & Stay which is kind of a Duplicate Script.
You can use the same functionality in your Business rule or any other server side script:
doInsertAndStay();
function doInsertAndStay() {
var saveMe = current;
if (typeof current.number != 'undefined' && current.number){
current.number = ""; // generate a new number
}
current.insert();
action.setRedirectURL(saveMe);
}
The GlideRecord function insert() duplicates a record and of course a new sys_id is used for the new record. As far as I know you are not able to define the sys_id by your self.

How to avoid affecting other queries when using posts_orderby?

In WordPress as you must already known, when using get_posts() or query_posts() or even WP_Query, it is not possible to order the returned posts by specifying a list of post ID in the order we want.
Instead we have to loop through the results and re-order them on the PHP side. This is a performance hit and a bad practice. Instead we should use built-in MySQL functions to retrieve the posts in the desired order upfront.
Thankfully there is the posts_orderby which can be used to specify a custom ORDERBY statement, like this:
// My list of post IDs in my custom order
$my_post_ids = array(1,3,2);
// Apply filter to the ORDERBY SQL statement
add_filter('posts_orderby', 'my_custom_orderby');
function my_custom_orderby($orderby_statement) {
global $my_post_ids;
$orderby_statement = 'FIELD(ID, '.implode(',',$my_post_ids).')';
return $orderby_statement;
}
// My custom query
$my_custom_query = new WP_Query(array('post_type' => 'post', 'post__in' => $my_post_ids);
However there is a problem with the above code, is that it will affect the order of all queries on the page! Including queries made by plugins, shortcodes, and so on.
Easy fix!
The simple way to fix this, is to apply the filter only one time, and remove it as soon as it is called, by putting a remove_filter() within the filter itself, so it is run only once:
// My list of post IDs in my custom order
$my_post_ids = array(1,3,2);
// Apply filter to the ORDERBY SQL statement
add_filter('posts_orderby', 'my_custom_orderby');
function my_custom_orderby($orderby_statement) {
// Disable this filter for future queries!
remove_filter(current_filter(), __FUNCTION__);
global $my_post_ids;
$orderby_statement = 'FIELD(ID, '.implode(',',$my_post_ids).')';
return $orderby_statement;
}
// My custom query
$my_custom_query = new WP_Query(array('post_type' => 'post', 'post__in' => $my_post_ids);
Because I set this filter just before my custom query, once I execute my custom query it should be filtered by the posts_orderby filter set above, which is then immediately disabled so it won't affect any future queries.
In theory, that's great, and it works great in most case scenarios!
An issue with WPML
However I have encountered a case when using the WPML plugin where this filter affects other queries than mine and causes errors. I believe the WPML plugin is creating a query of its own that is executed just before my own custom query, making my filter applies to the WPML query instead of mine!
Is there any possible way to add a check within the filter to make sure that it affects the correct query?
Thank you very much
Edit:
The fix for WPML
For information, while the accepted answer for this question is correct, it didn't solve the problem I was having with WPML. Here is how I fixed the WPML conflict:
// My list of post IDs in my custom order
$my_post_ids = array(1,3,2);
// Apply filter to the ORDERBY SQL statement
add_filter('posts_orderby', 'my_custom_orderby');
function my_custom_orderby($orderby_statement) {
// Disable this filter for future queries!
remove_filter(current_filter(), __FUNCTION__);
global $my_post_ids, $wpdb;
$orderby_statement = 'FIELD('.$wpdb->base_prefix.'posts.ID, '.implode(',',$my_post_ids).')';
return $orderby_statement;
}
// My custom query
$my_custom_query = new WP_Query(array('post_type' => 'post', 'post__in' => $my_post_ids);
This filter takes two parameters, $orderby and &$this. "this" being the WP_Query object. I'm not sure how to detect that WPML is making the call, but we can check that your call is the one being
made.
$my_post_ids = array(1,3,2);
add_filter( 'posts_orderby', 'my_custom_orderby', 10, 2 );
function my_custom_orderby( $orderby_statement, $object )
{
global $my_post_ids;
if( $my_post_ids != $object->query['post__in'] )
return $orderby_statement;
// Disable this filter for future queries!
remove_filter( current_filter(), __FUNCTION__ );
$orderby_statement = 'FIELD(ID, ' . implode( ',', $my_post_ids ) . ')';
return $orderby_statement;
}