Looping rows of entitydatasource - c#

First off.. I am new to asp.net and EF.
I have an EntityDatsource on my page I would like to loop through each row in the result set.
My goal is to dynamically build a page based on the values in the result set. Then to post the information back after it is edited by the user. My plan was to iterate each row on the page_load event. Currently I just have p-code in the area I would like to make this happen. The p-code is as follows
// foreach (DataRow row in AvailableDeviceConfigDataSource.enti Rows)
// {
// if sectionHeading <> lastSectionHeading
// {
// lastSectionHeading = sectionHeading
// AddSettingsSection(sectionHeading)
// }
// AddRowObjects
// }
Any guidance would be much appreciated.

In case anybody comes across this and is interested, I did solve my issue a while ago and figured I should post my answer for the benefit of others....
using (var context = new MyEntities())
{
string lastSectionHeading = "";
bool isFirstHeading = true;
var dynamicPageItems = context.view_dynamicPageItems;
foreach (var item in dynamicPageItems)
{
if (item.IsActive == 1)
{
if (!lastSectionHeading.Equals(item.CategoryId))
{
if (!isFirstHeading)
CloseSection();
lastSectionHeading = item.CategoryId;
AddSettingsSection(item.CategoryDescription);
isFirstHeading = false;
}
AddControl( item.DataType );
}
}
}

Related

How to efficiently edit data in a database?

The method is supposed to receive data from a server, check if new tokens have been added, and if there are, add them to the database. If the token already exists, update its status but don't add a new row in the table. This is the code I've written so far.
IEnumerable<Token> serverTokens = JsonConvert.DeserializeObject<IEnumerable<Token>>
(server.GetTokens().Content);
IEnumerable<Token> dbTokens = _tokenService.GetAllTokens();
foreach (var token in serverTokens)
{
var dbToken = dbTokens.Where(x => x.Symbol == token.Symbol).FirstOrDefault();
if (dbToken != null)
{
Token editedToken = dbToken;
editedToken.UpdatedOn = DateTime.Now;
editedToken.Active = token.Active;
_tokenService.AddToken(editedToken);
}
else
{
token.UpdatedOn = DateTime.Now;
_tokenService.AddToken(token);
}
}
dbContext.SaveChanges();
The AddToken method is just a simple AddOrUpdate operation.
public void AddToken(Token token)
{
_dbContext.Tokens.AddOrUpdate(token);
//_dbContext.SaveChanges();
}
Now, this code does what it's supposed to, however it's extremely slow. How would I go about optimizing it?
dbTokens.Where(x => x.Symbol == token.Symbol) is IEnumerable
So he will load it each time you call it on the loop.
Store in in a list before the loop
List<Token> dbTokens = _tokenService.GetAllTokens().ToList()

Dynamics CRM SDK: Execute Multiple Requests for Bulk Update of around 5000 Records

I have written a function to update Default Price List for all the Active Products on the CRM 2013 Online.
//The method takes IOrganization service and total number of records to be created as input
private void UpdateMultipleProducts(IOrganizationService service, int batchSize, EntityCollection UpdateProductsCollection, Guid PriceListGuid)
{
//To execute the request we have to add the Microsoft.Xrm.Sdk of the latest SDK as reference
ExecuteMultipleRequest req = new ExecuteMultipleRequest();
req.Requests = new OrganizationRequestCollection();
req.Settings = new ExecuteMultipleSettings();
req.Settings.ContinueOnError = true;
req.Settings.ReturnResponses = true;
try
{
foreach (var entity in UpdateProductsCollection.Entities)
{
UpdateRequest updateRequest = new UpdateRequest { Target = entity };
entity.Attributes["pricelevelid"] = new EntityReference("pricelevel", PriceListGuid);
req.Requests.Add(updateRequest);
}
var res = service.Execute(req) as ExecuteMultipleResponse; //Execute the collection of requests
}
//If the BatchSize exceeds 1000 fault will be thrown.In the catch block divide the records into batchable records and create
catch (FaultException<OrganizationServiceFault> fault)
{
if (fault.Detail.ErrorDetails.Contains("MaxBatchSize"))
{
var allowedBatchSize = Convert.ToInt32(fault.Detail.ErrorDetails["MaxBatchSize"]);
int remainingCreates = batchSize;
while (remainingCreates > 0)
{
var recordsToCreate = Math.Min(remainingCreates, allowedBatchSize);
UpdateMultipleProducts(service, recordsToCreate, UpdateProductsCollection, PriceListGuid);
remainingCreates -= recordsToCreate;
}
}
}
}
Code Description : There are around 5000 active product records in the System. So I am updating Default Price List for all of them using above code.
But, I am missing here something so that, it has updated only 438 records. It loops through the While statement correctly, but it is not updating all of them here.
What should be the Batchsize when we run this function for the First Time?
Any one can help me here?
Thank you,
Mittal.
You pass remainingCreates as the batchSize parameter but your code never references batchSize so you are just going to reenter that while loop every time.
Also, I'm not sure how you are doing all your error handling but you need to update your catch block so that it doesn't just let FaultExceptions pass-through if they don't contain a MaxBatchSize value. Right now, if you take a FaultException regarding something other than batch size it will be ignored.
{
if (fault.Detail.ErrorDetails.Contains("MaxBatchSize"))
{
var allowedBatchSize = Convert.ToInt32(fault.Detail.ErrorDetails["MaxBatchSize"]);
int remainingCreates = batchSize;
while (remainingCreates > 0)
{
var recordsToCreate = Math.Min(remainingCreates, allowedBatchSize);
UpdateMultipleProducts(service, recordsToCreate, UpdateProductsCollection, PriceListGuid);
remainingCreates -= recordsToCreate;
}
}
else throw;
}
Instead of reactive handling, i prefer proactive handling of the MaxBatchSize, this is true when you already know what is MaxMatchSize is.
Following is sample code, here while adding OrgRequest to collection i keep count of batch and when it exceeds I call Execute and reset the collection to take fresh batch.
foreach (DataRow dr in statusTable.Rows)
{
Entity updEntity = new Entity("ABZ_NBA");
updEntity["ABZ_NBAid"] = query.ToList().Where(a => a.NotificationNumber == dr["QNMUM"].ToString()).FirstOrDefault().TroubleTicketId;
//updEntity["ABZ_makerfccall"] = false;
updEntity["ABZ_rfccall"] = null;
updEntity[cNBAttribute.Key] = dr["test"];
req.Requests.Add(new UpdateRequest() { Target = updEntity });
if (req.Requests.Count == 1000)
{
responseWithResults = (ExecuteMultipleResponse)_orgSvc.Execute(req);
req.Requests = new OrganizationRequestCollection();
}
}
if (req.Requests.Count > 0)
{
responseWithResults = (ExecuteMultipleResponse)_orgSvc.Execute(req);
}

Out of Memory at line XXXX

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!

SPListItem Save conflict while Update

(1) var list1 = web.GetList("/lists/list1");
(2) var item1 = list1.GetItemById(10001);
(3) ...
take breakpoint here, open item with ID = 10001 for edit, change 'Title' fields and save it. Then run code follow:
(4)item1[SPBuiltInFieldId.Title] = "some text";
(5)item1.Update();
row (5) throws save conflict exception.
How can to lock item for edit at line (3)? Or any other approach to avoid conflict?
You have to check the SPListItem manually
try
{
var item = list.GetItemById(3);
item["MyField"] = "FooBar";
item.Update();
}
catch(SPException conflictEx)
{
// handle conflict by re-evaluating SPListItem
var item = list.GetItemById(3);
// ..
}
I don't know any other mechanism atm.
// *create a new SPWeb object for each list modification otherwise
we'll get Save Conflict*
from the following URL
http://platinumdogs.me/2010/01/21/sharepoint-calling-splist-update-causes-save-conflict-spexception/
exceptions
using (var thisWeb = featSite.OpenWeb(featWeb.ID))
{
try
{
var listUpdate = false;
var theList = thisWeb.Lists[att.Value];
// change list configuration
// .....
// commit List modifications
if (listUpate)
theList.Update();
}
catch
{
// log the event and rethrow
throw;
}
}
}
}
Another approach is using Linq to SharePoint, Linq to SharePoint offers you a conflict resolution mechanism
SharePoint's LINQ provider is querying for concurrent changes when you try to save changes you've made using the SubmitChanges method.
When a conflict has been found, a ChangeConflictException will be thrown.
foreach(var notebook in spSite.Notebooks)
{
notebook.IsTopNotebook = true;
}
try
{
spSite.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch(ChangeConflictException ex)
{
foreach(ObjectChangeConflict occ in spSite.ChangeConflicts)
{
if (((Notebook)occ.Object).Memory > 16)
{
foreach (MemberChangeConflict field in occ.MemberConflicts)
{
if (field.Member.Name == "IsTopNotebook")
{
field.Resolve(RefreshMode.KeepCurrentValues);
}
else
{
field.Resolve(RefreshMode.OverwriteCurrentValues);
}
}
}
else
{
occ.Resolve(RefreshMode.KeepCurrentValues);
}
}
spSite.SubmitChanges();
}

Retrieve all items from a SharePoint Field Choice Column

I am playing around with a SharePoint server and I am trying to programmatically add a service request to microsoft's call center application template. So far, I have had pretty good success. I can add a call for a specified customer and assign a specific support tech:
private enum FieldNames
{
[EnumExtension.Value("Service Request")]
ServiceRequest,
[EnumExtension.Value("Customer")]
Customer,
[EnumExtension.Value("Service Representative")]
ServiceRepresentative,
[EnumExtension.Value("Assigned To")]
AssignedTo,
[EnumExtension.Value("Software")]
Software,
[EnumExtension.Value("Category")]
Category
}
private void CreateServiceCall(string serviceCallTitle, string customerName, string serviceRep)
{
SPSite allSites = new SPSite(siteURL);
SPWeb site = allSites.AllWebs[siteName];
SPListItemCollection requestsList = site.Lists[serviceRequests].Items;
SPListItem item = requestsList.Add();
SPFieldLookup customerLookup = item.Fields[FieldNames.Customer.Value()] as SPFieldLookup;
item[FieldNames.ServiceRequest.Value()] = serviceCallTitle;
if (customerLookup != null)
{
using (SPWeb lookupWeb = allSites.OpenWeb(customerLookup.LookupWebId))
{
SPList lookupList = lookupWeb.Lists.GetList(new Guid(customerLookup.LookupList), false);
foreach (SPListItem listItem in lookupList.Items)
{
if (listItem[customerLookup.LookupField].ToString() != customerName) continue;
item[FieldNames.Customer.Value()] = new SPFieldLookupValue(listItem.ID, customerName);
break;
}
}
}
SPUserCollection userCollection = site.SiteUsers;
if (userCollection != null)
{
foreach (SPUser user in userCollection)
{
if (user.Name != serviceRep) continue;
item[FieldNames.AssignedTo.Value()] = user;
break;
}
}
item.Update();
site.Close();
allSites.Close();
}
I added two custom columns (category, software) to the default list:
I populated both of these columns inside of SharePoint, now I want to retrieve that data so I can use it in the code snippet I posted to assign the proper category/software etc to the call. I have not been able to get the list in the code, I have tried using a item["Software"], site.Lists["Software"] and a couple of others, but so far all I have come up is null.
Can anyone point me in the right direction for this? Thanks!
SPFieldMultiChoice and related fields have a Choices property:
SPFieldMultiChoice software = item.Fields[FieldNames.Software.Value()] as SPFieldMultiChoice;
StringCollection softwareChoices = software.Choices;
If you need to set a value on the field, use the SPFieldMultiChoiceValue type:
SPFieldMultiChoiceValue values = new SPFieldMultiChoiceValue();
values.Add("Choice 1");
values.Add("Choice 2");
item[FieldNames.Software.Value()] = values;

Categories

Resources