I've revised my code and question to better reflect what I'm trying to accomplish.
Background: I have different layer interfaces as part of my project.
Service Layer - handles my business logic, validates entries, (the brains)
Data Access Layer - simply executes the methods or functions it is passed
Aspx & aspx.cs files where the methods need to take place (i.e the user interface)
Here is my code for the ConnectionTypeSetup.aspx.cs file, I've also marked the line where there is an error:
protected void uxSaveBtn_Click(object sender, EventArgs e)
{
var accountTrackersvc = new AccountTrackerSvc();
//Insert or update record
var result = ViewState["ConnectionTypeID"] == null ?
accountTrackersvc.InsertConnectionType(uxConnectionTypeDescTxt.Text.Trim(),
CommonSVC.GetUserInfoFormattedFromSession())
/*Error on this line */ : accountTrackersvc.UpdateConnectionType(DataConverter.StringToInteger(ViewState["ConnectionTypeID"].ToString()),
uxConnectionTypeDescTxt.Text.Trim(),
Enums.GetIsDisabledByItemStatusValue(SafeValueAccessor.GetControlValue(uxStatusDdl)),
CommonSVC.GetUserInfoFormattedFromSession(),"Default",false);
//Check result
if(result.Successful)
{
uxInfoMsg.DisplayMessage(result.Message, InfoMessage.InfoMessageType.Success);
BindGridContent();
uxPopupMdl.Hide();
}
else
{
uxModalInfoMsg.DisplayMessage(result.Message, InfoMessage.InfoMessageType.Failure);
uxPopupMdl.Show();
}
// Hide progress indicator
Master.HideProgressIndicator();
The service layer which again handles my business logic is formatted as follows. Please note there are 2 separate methods being used and Insert and Update:
public BO.OperationResult InsertConnectionType(string connectionTypeDesc, string createdBy)
{
var operationResult = new BO.OperationResult();
// connection type description required
if (connectionTypeDesc.Trim().Length <= 0)
{
operationResult.Successful = false;
operationResult.Message += "Connection type description is required";
}
//Createdby required
if (createdBy.Trim().Length <= 0)
{
operationResult.Successful = false;
operationResult.Message += "A record has not been saved in the form this entry was created by";
}
if (operationResult.Successful)
{
operationResult.DBPrimaryKey = new DAL.AccountTrackerDAL().InsertConnectionType(connectionTypeDesc.Trim(), createdBy);
operationResult.Message = "Account Access Level Saved Successfully";
}
return operationResult;
}
2nd Business logic Method and code for update:
public BO.OperationResult UpdateConnectionType(int connectionTypeID, string connectionTypeDesc,bool isDisabled,string lastUpdatedBy)
{
var operationResult = new BO.OperationResult();
if (connectionTypeDesc.Trim().Length <= 0)
{
operationResult.Successful = false;
operationResult.Message += "Connection Type Description has not successfully updated.";
}
if (lastUpdatedBy.Trim().Length <= 0)
{
operationResult.Successful = false;
operationResult.Message += "Last updated by must be entered.";
}
if (operationResult.Successful)
{
operationResult.DBPrimaryKey = new DAL.AccountTrackerDAL().UpdateConnectionType(connectionTypeID, lastUpdatedBy, connectionTypeDesc, isDisabled);
operationResult.Message = "Account Access Level Saved Successfully";
}
return operationResult;
}
Lastly, I'll only include the method signitures for the DAL layer as I think that should be enough and not saturate this question with code.
Update ConnectionType
public int UpdateConnectionType(int connectionTypeID, string lastUpdatedBy, string connectionTypeDesc, bool isDisabled)
Insert ConnectionType
public int InsertConnectionType(string connectionTypeDesc, string createdBy)
My current error reads: No overload for method UpdateConnectionType takes 6 arguments. I've tried to default the values only to receive this error. Any feedback would be appreciated, thanks!
When you call InsertConnectionType, you MUST provide four (4) parameters. That is how the method is written, so that is what you must do:
accountTrackersvc.InsertConnectionType(
uxConnectionTypeDescTxt.Text.Trim(),
CommonSVC.GetUserInfoFormattedFromSession(),
"Default", false)
The parameters above would pass the compiler.
If you absolutely insist on using only two (2) parameters, you could create an overload method:
public BO.OperationResult InsertConnectionType(string connectionTypeDesc, int connectionTypeID)
{
return InsertConnectionType(connectionTypeDesc, connectionTypeID, "Default", false);
}
UPDATE
To add an overload for your UpdateConnectionType method, try something like this:
public BO.OperationResult UpdateConnectionType(int connectionTypeID, string connectionTypeDesc)
{
var operationResult = new BO.OperationResult();
if (connectionTypeDesc.Trim().Length <= 0)
{
operationResult.Successful = false;
operationResult.Message += "Connection Type Description has not successfully updated.";
}
if (operationResult.Successful)
{
operationResult.DBPrimaryKey = new DAL.AccountTrackerDAL().UpdateConnectionType(connectionTypeID, "Default", connectionTypeDesc, false);
operationResult.Message = "Account Access Level Saved Successfully";
}
return operationResult;
}
Of course, make sure you replace the text "Default" and the Boolean value false with whatever is appropriate for your class.
Related
I am using the Xi interface to retrieve data from an OPC .NET server. The issue that I am having though is that the server seems to be incorrectly identifying a parameter as not being historized.
Even though all the information from DeltaV indicates that the corresponding parameter for the ObjectAttributes object returned from the server should indicate that it is collecting history, the IsCollectingHistory property actually indicates that it is false.
History collection is enabled:
The parameter in question is in the history collection:
I won't include the screenshot but I can also open the historical trend for that parameter. But as you can see below, when I inspect the retrieved object while debugging, it says that it is not being historized.
Here is some of the code that I am using:
FindCriteria criteria = createCriteria(path, false);
List<Parameter> parameters = new List<Parameter>();
IEnumerable<ObjectAttributes> enumerableObject;
int i = 0;
try
{
enumerableObject = iContext.FindObjects(criteria, 50);
}
catch (System.ServiceModel.FaultException)
{
//This error is thrown when no data is returned.
return null;
}
A few lines down, I then do some object initialization for my Parameter object, assigning it the properteries from the object that was received from the server. It is not shown below but I then add my Parameter object to a collection if it is being historized. It never gets added to the collection because the IsCollectingHistory property is always false.
enumerableObject = enumerableObject.Skip(1);
foreach (ObjectAttributes oa in enumerableObject)
{
Parameter _parameter = new Parameter
{
IsHistorized = oa.IsCollectingHistory,
IsLeaf = oa.IsLeaf
};
//...
Any ideas on where I am going wrong?
Edit:
After trying MotteAndBailey's answer, an error is thrown at the call to AddNewDataObjectToDataJournalList. The message associated with it is "The OPC HDA Create Browse failed".
Below is a screenshot of the error in a message box when using HDAprobe:
Some info on properties in OPC.NET -
The Xi server wraps the OPCDA and OPCHDA servers. The item properties (attributes) available on each server and the means of accessing them using Classic (DCOM) OPC vary considerably.
OPCDA
The OPCDA server provides a method for determining item properties:
IOPCItemProperties::GetItemProperties()
This call provides the client with a way to read all an item’s attribute values using the item ID (string path for the item in the Server’s address space) and propertyID. The Xi server uses this call when performing a FindObjects() call. FindObjects() returns all the properties exposed by the OPCDA server for an item.
OPCHDA
The OPCHDA server has a method for determining item properties, but it requires the item handle not the ItemID/path:
IOPCHDA_SyncRead::ReadAttribute()
As a result, the FindObjects() call for an OPCHDA server through Xi only returns the item ID property. The other attributes are set to defaults. To determine what the actual values of the other properties are a user must add the item to a list and call ReadAttribute() on the specific property they wish to see.
In summary, the OPCDA server works pretty much like you would expect and returns the object properties in a single method call; however, the OPCHDA server requires an additional step to get all the object properties.
The sample code will produce an Xi Journal list with only the on-scan history items.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xi.Client.Base.API;
using Xi.Client.Base;
using Xi.Contracts;
using Xi.Contracts.Data;
using Xi.Contracts.Constants;
using System.ServiceModel.Description;
using Xi.Client.CommonDialogs;
using System.Runtime.Serialization;
namespace ConsoleFindObjectsHDA
{
public class DotNetSupport
{
IXiEndpointDiscovery iEndpointDiscovery;
IXiContext iContext;
IXiEndpointBase readEndpoint;
ServiceEndpoint RMSvcEndpt;
//the list of items the user is trying to read
IXiDataJournalList iDataJournalList;
public void GetSomeData()
{
//get a connection to an OPC.NET server
if (Connect())
{
//we have to have a list to add a tag to and hold returned datasets
if (CreateJournalList())
{
//now use the list to add items and read their attributes - only "good" ones will be left on the list
ListAllHDAItemsOnScan();
if (iDataJournalList.Count() > 0)
{
//at this point we <should> have a DataJournalList containing only the HDA items on scan
//we can use the normal data read methods to get history for the items if we wish
// <do some history thing here>
}
else
{
Console.WriteLine("\nThere were no points on-scan in the historian");
}
Console.WriteLine("\nPress <return> to exit program");
Console.ReadLine();
}
////clean up if we have open connections/contexts
Cleanup();
}
}
//we will use FindObjects to browse all the leaves in the HDA server, then add them one-by-one to a datalist
//when we query their on-scan property and it is true we leave them on the list
//...if not, we remove them (giving us a list of the good HDA points)
void ListAllHDAItemsOnScan()
{
FindCriteria criteria = GetLeafCriteria();
IEnumerable<ObjectAttributes> enumerableObject;
try
{
//ask the server for a list of leaves...up to 50 max returned in this call
enumerableObject = iContext.FindObjects(criteria, 50);
//for each string itemID: add it to the list, read the attribute, and remove it from the list if not on-scan
foreach (ObjectAttributes oa in enumerableObject)
{
//we do not have to commit this because we have indicated the operation is NOT prep-only
Console.WriteLine("Adding OPCHDA item {0}.", oa.InstanceId.LocalId);
IXiHistoricalDataObject ixObject = iDataJournalList.AddNewDataObjectToDataJournalList(oa.InstanceId, false);
//we are getting the CURRENT (from NOW -to- NOW) item status
FilterCriterion fc1 = GetFilterCriteriaDateTime(DateTime.Now);
//tell the server what property (attribute) we want to read
List<TypeId> lstp = new List<TypeId>();
TypeId typeit = new TypeId("", "", DVServerAttributes.DELTAV_DVCH_ON_SCAN.ToString());
lstp.Add(typeit);
//read the property from the server
iDataJournalList.ReadJournalDataProperties(fc1, fc1, ixObject, lstp);
//find the current item and check it for "on-scan"
if (ixObject != null)
{
if (ixObject.PropertyValues.First().PropertyValues.UintValues.First() == 1)
{
Console.WriteLine("OPCHDA item {0} is on-scan.\n", oa.InstanceId.LocalId);
}
else
{
if (ixObject.PrepForRemove())
{
Console.WriteLine("OPCHDA item {0} is not on-scan. Removing item.\n", oa.InstanceId.LocalId);
iDataJournalList.CommitRemoveableElements();
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception in FindObjects(). The exception is:{0}\n", ex.Message);
}
}
//create a filtercriterion for a specific date time - this is an EQUAL (not > or <) comparison operator
public FilterCriterion GetFilterCriteriaDateTime(DateTime dtChosenTime)
{
//simple timestamp filter which is used by the read call
FilterCriterion filterCriterion = null;
// this is a timestamp
string filterOperand = FilterOperandNames.Timestamp;
//make the given time with UTC/Local set to local time just to be sure
DateTime dtTmp1 = DateTime.SpecifyKind(dtChosenTime, DateTimeKind.Local);
object comparisonValue = dtTmp1;
//timestamp equal to this one
uint oper = FilterOperator.Equal;
//create the filter
filterCriterion = new FilterCriterion()
{
OperandName = filterOperand,
Operator = oper,
ComparisonValue = comparisonValue,
};
return filterCriterion;
}
//create a filtercriterion for leaves (OPCHDA items)
public FilterCriterion GetLeafFilterCriterion()
{
//simple filter for leaves
FilterCriterion filterCriterion = null;
// what this criterion applies to
string filterOperand = FilterOperandNames.BranchOrLeaf;
//Must equal "LEAF" to match
uint oper = FilterOperator.Equal;
//create the filter
filterCriterion = new FilterCriterion()
{
OperandName = filterOperand,
Operator = oper,
ComparisonValue = "LEAF",
};
return filterCriterion;
}
//set up the FindCriteria search of the server
public FindCriteria GetLeafCriteria()
{
FindCriteria findCriteria = null;
findCriteria = new FindCriteria();
//our browse starts at the root - NULL means "continue browsing from where you are"
findCriteria.StartingPath = new ObjectPath("//", "HDA");
//a list of OR-ed filter criteria (we have only one)
ORedFilters orthefilters = new ORedFilters();
//the FilterCriteria list (there is only one criterion)
orthefilters.FilterCriteria = new List<FilterCriterion>();
orthefilters.FilterCriteria.Add(GetLeafFilterCriterion()); //we want leaves
//add our OR-ed filter to the filterset filters list (whew!)
findCriteria.FilterSet = new FilterSet();
findCriteria.FilterSet.Filters = new List<ORedFilters>();
findCriteria.FilterSet.Filters.Add(orthefilters);
return findCriteria;
}
//connect to the OPC.NET server and get a read endpoint
public bool Connect()
{
//set this to point to your OPC.Net server
string serverUrl = "http://localhost:58080/XiServices/ServerDiscovery";
bool bReturnVal = false;
try
{
Console.WriteLine("Getting Endpoint Discovery from server:\n{0}\n", serverUrl);
//This class is used to locate a server and obtain its list of ServiceEndpoints.
iEndpointDiscovery = new XiEndpointDiscovery(serverUrl) as IXiEndpointDiscovery;
//we have the server...now check for endpoints
//there should always be TCP endpoints for a DeltaV OPC.NET server so we do not search HTTP and Named Pipes to find one
//and we do not consider choosing the fastest option between the three (TCP/HTTP/NamedPipes). We just use the TCP/IP one.
// GetServiceEndpointsByBinding searches the list of endpoints on the XiEndpointDiscovery connection with the specified contractType and binding type.
// We use the ResourceManagement endpoint to find the the other open endpoints on the server (some might be disabled)
IEnumerable<ServiceEndpoint> resourceEndpoints = iEndpointDiscovery.GetServiceEndpointsByBinding(typeof(IResourceManagement).Name, typeof(System.ServiceModel.NetTcpBinding));
//use the first (probably only) resource endpoint for TCP/IP to open a context between client and server
if ((resourceEndpoints != null) && (resourceEndpoints.Count() > 0))
{
var serviceEndpoints = resourceEndpoints as IList<ServiceEndpoint> ?? resourceEndpoints.ToList();
//pick the first RM endpoint we found
RMSvcEndpt = ((IList<ServiceEndpoint>)serviceEndpoints).First();
//Open the Context using the RM endpoint and some other values including timeout, what we want to read (HDA), and the GUID for this context
Console.WriteLine("Opening Client Context with Initiate\n");
iContext = XiContext.Initiate(RMSvcEndpt,
iEndpointDiscovery.ServerEntry,
300000,
(uint)ContextOptions.EnableJournalDataAccess, //HDA
(uint)System.Threading.Thread.CurrentThread.CurrentCulture.LCID,
Guid.NewGuid().ToString());
if (iContext != null)
{
//find a read endpoint using the XiEndpointDiscovery connection
IEnumerable<ServiceEndpoint> readseps = iEndpointDiscovery.GetServiceEndpointsByBinding(typeof(IRead).Name, RMSvcEndpt.Binding.GetType());
//if we found at least one read endpoint, connect the context to it
readEndpoint = null;
if (readseps != null)
{
Console.WriteLine("Adding Read endpoint to Context\n");
ServiceEndpoint sep = readseps.ElementAt<ServiceEndpoint>(0);
readEndpoint = iContext.OpenEndpoint(sep, 30000, new TimeSpan(5000));
if (readEndpoint != null)
{
bReturnVal = true; //everything went OK
}
else
{
Console.WriteLine("Unable to add Read endpoint to Context\n");
bReturnVal = false; //failed
}
}
}
else
{
Console.WriteLine("Unable to open Client Context\n");
bReturnVal = false;
}
}
}
catch (Exception)
{
bReturnVal = false;
}
return (bReturnVal);
}
public bool CreateJournalList()
{
bool retval = false;
try
{
//create a new list of HDA objects for this read
// update buffer
// rate rate filterset(not used here)
iDataJournalList = iContext.NewDataJournalList(1000, 1000, null);
if (iDataJournalList != null)
{
//we need to add the list to a read endpoint to give it data access
iDataJournalList.AddListToEndpoint(readEndpoint);
//enable the list so we can connect the items we add to it and read data
iDataJournalList.EnableListUpdating(true);
retval = true;
}
}
catch (Exception)
{
retval = false;
}
return retval;
}
public void Cleanup()
{
if (iContext != null)
{
iContext.Dispose();
}
}
} //class DotNetSupport
}
namespace ConsoleFindObjectsHDA
{
public class DVServerAttributes
{
//some DeltaV-specific OPCHDA attributes
public static uint DELTAV_DESC = 2147483650;
public static uint DELTAV_ENG_UNITS = 2147483651;
public static uint DELTAV_EU100 = 2147483666;
public static uint DELTAV_EU0 = 2147483667;
public static uint DELTAV_DVCH_LAST_DOWNLOAD = 2147483682;
public static uint DELTAV_DVCH_ON_SCAN = 2147483683;
public static uint DELTAV_NAMED_SET = 2147483698;
}
}
I've found FluentValidation only couple of hours ago and I want to rewrite all my validation logic so it will use only FV.
The issue that I have ATM is that I would like to use data coming from input as a parameter for DomainExists() method. Is it possible or do I have to figure out a way around FV to achieve that?
public QuoteValidator()
{
// hardcoded because don't know how to pass input string to RuleFor
var inputeddomain = "http://google.com";
RuleFor(r => r.Domain).NotEqual(DomainExists(inputeddomain));
}
// checks if inputeddomain is in repository (SQL DB)
private string DomainExists(string inputeddomain)
{
var context = new QuoteDBContext().Quotes;
var output = (from v in context
where v.Domain == inputeddomain
select v.Domain).FirstOrDefault();
if (output != null) { return output; } else { return "Not found"; }
}
Thanks to #bpruitt-goddard hint I got that to work. Here's a solution to my problem (hope it will help somebody).
public QuoteValidator()
{
RuleFor(r => r.Domain).Must(DomainExists).WithMessage("{PropertyValue} exists in system!");
}
private bool DomainExists(string propertyname)
{
var context = new QuoteDBContext().Quotes;
var output = (from v in context
where v.Domain == propertyname
select v.Domain).FirstOrDefault();
if (output != null) { return false; } else { return true; }
}
You can use FluentValidation's Must method to pass in extra data from the input object.
RuleFor(r => r.Domain)
.Must((obj, domain) => DomainExists(obj.InputDomain))
.WithErrorCode("MustExist")
.WithMessage("InputDomain must exist");
Although this will work, it is not recommended to check for database existence in the validation layer as this is verification versus validation. Instead, this kind of check should be done in the business layer.
Trying to unit test functions which access a entity framework. So i tried to put all the entity code into the test function below? However it stops at the Linq statement; obviously trying to access the database is too much drama for it. Maybe a work around would be too to create a replica database within the unit test function based on sql lite or compact;(Its not a big database anyways) then execution would not have to leave the test function? Is this possible and how would i implement it?
public void RetreiveKeyFnTest()
{
StegApp target = new StegApp(); // TODO: Initialize to an appropriate value
string username = "david"; // TODO: Initialize to an appropriate value
string password = "david1"; // TODO: Initialize to an appropriate value
string ConnectionString = ConfigurationManager.ConnectionStrings["DatabaseEntities"].ToString();
var dataContext = new DatabaseEntities(ConnectionString);
var user = dataContext.Users.FirstOrDefault(u => u.Username.Equals(username) && u.Password.Equals(password));
Assert.IsNotNull(user);
//target.RetreiveKeyFn(username, password);
//Assert.IsInstanceOfType(target.RetreiveLogs,typeof(DataAccess));
//Assert.IsInstanceOfType(target.p);
//Assert.IsNotNull(target.RetreiveLogs.AuthenitcateCredentials(username,password));
//Assert.Inconclusive("A method that does not return a value cannot be verified.");
}
Below is the code i am trying to test:
public void RetreiveKeyFn(string username, string password)
{
BusinessObjects.User p = RetreiveLogs.AuthenitcateCredentials(username,password);
if (p != null)
{
if (RetreiveLogs.RetreiveMessages(p.UserId) == null)
{
DisplayLogs.Text = "Sorry No messages for you recorded in Database, your correspondant might have chose not to record the entry";
}
else
{
MessageBox.Show("LogId = " + RetreiveLogs.RetreiveMessages(p.UserId).LogId + "\n" +
"UserId = " + RetreiveLogs.RetreiveMessages(p.UserId).UserId + "\n" +
"Message Key = " + RetreiveLogs.RetreiveMessages(p.UserId).MessageKey + "\n" + "PictureId = " + RetreiveLogs.RetreiveMessages(p.UserId).PictureId +
" Date & time = " + RetreiveLogs.RetreiveMessages(p.UserId).SentDateTime);
DisplayLogs.Visible = true;
}
}
else
{
MessageBox.Show("Please enter your correct username and password in order to retreive either key, image or both from Databse");
}
}
First, you should be able to access the same database in your test application as the one you're using in your main/actual application. You just need to make sure that your Test project contains your connection string in its own App.config.
The initialization of the context should be done either inside your StegApp(), or you should be able to pass a context to your StegApp() from a different scope. From what I read of your code, your StegApp() will not be able to access the dataContext variable you created.
Your test for null user already happens inside the RetrieveKeyFn() under the AuthenticateCredentials() method so there's no need for the first "Assert.IsNotNull(user)". I would recommend separating your business logic for RetrieveKeyFn from your UI behaviors so that you can easily do unit tests. You can bind the "Messagebox" operations to say a button click event handler which calls just RetrieveKeyFn(). I would suggest maybe something like this:
public class StegApp
{
public DatabaseEntities context;
//other properties
public StegApp()
{
//assuming your DatabaseEntities class inherits from DbContext.
//You should create other constructors that allow you to set options
//like lazy loading and mappings
this.context = new DatabaseEntities();
}
//ASSUMING YOUR RetrieveLogs.RetrieveMessages() function returns
//a Message object. replace this type with whatever type the
//RetrieveLogs.RetrieveMessages() method returns.
public Message RetrieveKeyFn (string username, string password)
{
BusinessObjects.User p = RetreiveLogs.AuthenitcateCredentials(username,password);
if (p != null)
{
var message = RetrieveLogs.RetrieveMessages(p.UserId);
if (message == null)
// handle behavior for no messages. In this case
// I will just create a new Message object with a -1 LogId
return new Message {LogId =-1};
else
return message;
}
else
//handle behavior when the user is not authenticated.
//In this case I throw an exception
throw new Exception();
}
//on your button click handler, do something like:
// try
// {
// var message = RetrieveKeyFn(txtUsername.Text.Trim(), txtPassword.Text.Trim());
// if (message.LogId == -1)
// DisplayLogs.Text = "Sorry No messages for you recorded in Database, your correspondant might have chose not to record the entry";
// else
// {
// MessageBox.Show("Log Id = " + message.LogId)
// etc. etc. etc.
// }
// }
// catch
// {
// MessageBox.Show ("user is not authenticated");
// }
}
When you do your unit test, remember to have the appropriate configuration strings in your test project's App.Config If the app.config does not yet exist, go ahead and create one. You should create tests for all possibilities (i.e. 1) user is valid, you get the message, 2) user is valid, there are no messages, 3) user is invalid).
Here's an example for case 2
[TestMethod]
public void RetrieveKeyFnTest1()
{
StegApp target = new StegApp(); // this creates your context. I'm assuming it also creates your RetrieveLogs object, etc
var username = "UserWithNotMessages"; //this user should exist in your database but should not have any messages. You could insert this user as part of your TestInitialize method
var password = "UserWithNotMessagesPassword"; //this should be the proper password
var message = target.RetrieveKeyFn(username, password);
Assert.AreEqual (-1, message.LogId);
}
I got my unit tests to work fine. The mistake i had was not to copy the app.config file into the test project! Although to be honest i expected Visual studio would have done that anyways.
can anyone help me how to resolve the out of memory error on my asp page? im using linq to sql.. after adding data several data.. like more than 10 rows. in the grid. an out of memory error occurs.. attached herewith is my add function..
public ServiceDetail checkservicedetailid()
{
string ServiceName = ViewState["Tab"].ToString();
ServiceDetail checkservicedetailid = ServiceDetails_worker.get(a => a.ServiceName == ServiceName && a.MarginAnalysisID == checkmarginanalysisid().MarginAnalysisID).SingleOrDefault();
return checkservicedetailid;
}
public IEnumerable<ServiceDetail> get(Expression<Func<ServiceDetail, Boolean>> express)
{
return ServiceDetailsDB.ServiceDetails.Where(express);
}
protected void btnSaveEmptyOC_Click(object sender, EventArgs e)
{
try
{
if (checkservicedetailid() != null)
{
CashExpense tblCashExpenses = new CashExpense();
Guid CashExpensesID = Guid.NewGuid();
tblCashExpenses.CashExpensesID = CashExpensesID;
tblCashExpenses.ServiceDetailsID = checkservicedetailid().ServiceDetailsID;
tblCashExpenses.Description = txtDescriptionEmptyOC.Text;
tblCashExpenses.Quantity = Decimal.Parse(txtQTYEmptyOC.Text);
tblCashExpenses.UnitCost = Decimal.Parse(txtUnitCostEmptyOC.Text);
tblCashExpenses.CreatedBy = User.Identity.Name;
tblCashExpenses.DateCreated = DateTime.Now;
tblCashExpenses.CashExpensesTypeID = "OTHER";
CashExpenses_worker.insert(tblCashExpenses);
CashExpenses_worker.submit();
//Clear items after saving
txtDescriptionEmptyOC.Text = "";
txtQTYEmptyOC.Text = "";
txtUnitCostEmptyOC.Text = "";
ValidationMessage.ShowValidationMessage(MessageCenter.CashExpenseMaintenace.InsertOC2, "SaveEmptyOC", this.Page);
MyAuditProvider.Insert(this.GetType().ToString(), ViewState["MarginAnalysisID"].ToString(), MessageCenter.Mode.ADD, MessageCenter.CashExpenseMaintenace.InsertOC2, Page.Request, User);
divOtherCost.Visible = false;
grd_othercost.Visible = true;
btnaddothercost.Visible = true;
}
else
{
//Displays a Message on the Validation Summary (Service Id does not exist)
ValidationMessage.ShowValidationMessage(MessageCenter.CashExpenseMaintenace.SaveServiceDetailOC, "SaveEmptyOC", this.Page);
}
}
catch
{
//Displays a Message on the Validation Summary (Error on Saving)
ValidationMessage.ShowValidationMessage(MessageCenter.CashExpenseMaintenace.InsertOCError, "SaveEmptyOC", this.Page);
}
finally
{
//Rebinds the Grid
populategrd_othercost();
}
}
I'm guessing from your code here:
ServiceDetail checkservicedetailid = ServiceDetails_worker.get(
a => a.ServiceName == ServiceName &&
a.MarginAnalysisID == checkmarginanalysisid().MarginAnalysisID
).SingleOrDefault();
that .get() is taking a Func<SomeType, bool>, and you are doing something like:
var row = dbCtx.SomeTable.Where(predicate);
(please correct me here if I'm incorrect)
This, however, is using LINQ-to-Objects, meaning: it is loading every row from the table to the client and testing locally. That'll hurt memory, especially if a different db-context is created for each row. Additionally, the checkmarginanalysisid() call is being executed per row, when presumably it doesn't change between rows.
You should be testing this with an Expression<Func<SomeType, bool>> which would be translated to TSQL and executed at the server. You may also need to remove untranslatable methods, i.e.
var marginAnalysisId = checkmarginanalysisid().MarginAnalysisID;
ServiceDetail checkservicedetailid = ServiceDetails_worker.get(
a => a.ServiceName == ServiceName &&
a.MarginAnalysisID == marginAnalysisId
).SingleOrDefault();
where that is get(Expression<Func<SomeType, bool>>).
I tried all of the solution given to me both by my peers as well as the solution provided here, from GC.Collect, to disposing linq datacontext after use etc. however the error keeps on occurring, i then tried to remove the update panel, Ive read a site that showed how ridiculous update panel when it comes to handling data esp when a function is done repeatedly. And poof! the memory problem is gone!
I am trying to implement prepared staments in my code as a way of adding parameters to sql commands that are retrieved from a table held in any generic server. I cannot seem to get it right. I get the following error:
ORA-00936: missing expression
ORA-00936: missing expression
Prepare Statement: select VALUE from RWOL_CONFIGURATION where ID = #ItemId
My guess is that it just isn't replacing the value but I dont know what I am missing.
I am trying the following to achieve the desired result. I create my object, get a query string out of our table in the database, add that to the command, add parameters to a list object and then use the final method shown below to tie it all together and run the query:
//This function gets me a config item from the database
private string GetConfigurationItem(string itemId)
{
//new database connection object
OleDataBaseConnection oleDataBaseConnection = new OleDataBaseConnection();
//todo get this query from the sql factory
SqlFactory sqlFactory = new SqlFactory();
//This method gets the query string from the database
string sqlQuery = sqlFactory.GetQueryString("GET_CONFIGURATION_ITEM", m_dialect);
if (!String.IsNullOrEmpty(sqlQuery))
{
//add parameter to list
oleDataBaseConnection.AddStoredProcedureParameter("#ItemId", itemId);
//execute the sql command after adding the parameters to the command
oleDataBaseConnection.OleExecutePrepareStatementWithParametersQuery(sqlQuery);
string returnValue = oleDataBaseConnection.NextRecord() ? oleDataBaseConnection.GetFieldById(0) : "Error";
oleDataBaseConnection.Close();
return returnValue;
}
else
{
return "ERROR";
}
}
//adds the parameters to list objects ready for the next method
public void AddParameter(string parameter, object value)
{
m_parameterName.Add(parameter);
m_parameterValue.Add(value);
} // End of void AddParameter()
/// <summary>
/// Executes a command with the parameters passed to AddParameter(parameterName, parameterValue) and creates a recordset.
/// </summary>
///
/// <param name="commandName">The name of the stored procedure to execute.</param>
public bool OleExecutePrepareStatementWithParametersQuery(string commandName)
{
if (String.IsNullOrEmpty(commandName))
{
return false;
}
try
{
PrepareConnection();
m_oleDatabaseCommand.CommandText = commandName;
m_oleDatabaseCommand.CommandType = CommandType.StoredProcedure;
if (m_storedProcedureParameterName.Count != 0)
{
for (int i = 0; i < m_storedProcedureParameterName.Count; i++)
{
m_oleDatabaseCommand.Parameters.AddWithValue(m_storedProcedureParameterName[i], m_storedProcedureParameterValue[i]);
}
m_storedProcedureParameterName.Clear();
m_storedProcedureParameterValue.Clear();
}
m_hasRecordSet = true;
m_oleDatabaseDataReader = m_oleDatabaseCommand.ExecuteReader();
return true;
}
catch (Exception ex)
{
if (QueueErrors)
{
QueuedErrorsList.AppendLine(ex.Message);
QueuedErrorsList.AppendLine("Prepare Statement: " + storedProcedureName);
QueuedErrorsList.AppendLine();
QueuedErrorCount++;
return false;
}
try
{
Close();
}
catch
{
}
throw new Exception(ex.Message + "\r\n\r\nPrepare Statement: " + storedProcedureName);
}
} // End of void OleExecutePrepareStatementWithParametersQuery()
Sorry if there is a lot of code but it is fairly straightforward and I thought it would help with the problem.
Is there anything obvious that would stop this from working?
The problem is that the OleDB provider does not support named parameters in the query.
This:
select VALUE from RWOL_CONFIGURATION where ID = #ItemId
Should be:
select VALUE from RWOL_CONFIGURATION where ID = ?
See OleDbParameter on MSDN for examples.