MARS in SQL Server 2000 - asp.net-mvc

I am working in ASP.Net MVC 1.0 and SQL Server 2000 using Entity Framework.
My faulty controller code is given below:
int checkUser = id ?? 0;
string userNameFromNew, userNameToNew;
if (checkUser == 1)
{
userNameFromNew = "U" + Request.Form["usernameFrom"];
userNameToNew = "U" + Request.Form["usernameTo"];
}
else
{
userNameFromNew = "C" + Request.Form["usernameFrom"];
userNameToNew = "C" + Request.Form["usernameTo"];
}
var rMatrix = from Datas in repository.GetTotalRightData()
where Datas.UserName == userNameFromNew.Trim()
select Datas;
Right_Matrix RM = new Right_Matrix();
foreach(var Data in rMatrix)
{
RM.Column_Id = Data.Column_Id;
RM.ProMonSys_Right = Data.ProMonSys_Right;
RM.UserName = userNameToNew;
UpdateModel(RM);
this.repository.AddRightTransfer(RM);
}
return RedirectToAction("RightTransfer");
My faulty model code is given below:
public void AddRightTransfer(Right_Matrix RM)
{
context.AddObject("Right_Matrix", RM);
context.SaveChanges();
}
My code shows error once it is in the model code stating the DataReader is already open and I need to close it first.
Please suggest a workaround.

Try moving the AddRightTransfer loop out of the LINQ foreach, and into a separate one. I think LINQ is executing the first add before the database result set is closed. By moving the call to AddRightTransfer into a second foreach, you should avoid the problem, if that's what is happening.
Here's an example:
List<Right_Matrix> matrixes = new List<Right_Matrix>();
foreach (var Data in rMatrix)
{
Right_Matrix rm = new Right_Matrix();
rm.Column_Id = Data.Column_Id;
rm.ProMonSys_Right = Data.ProMonSys_Right;
rm.UserName = userNameToNew;
UpdateModel(rm);
matrixes.Add(rm);
}
foreach (var rm in matrixes)
{
this.repository.AddRightTransfer(rm);
}

The problem is that you are modifying the database while still iterating over it. Either finish the query before modifying, like this:
foreach(var Data in rMatrix.ToArray())
Or don't modify the database in your loop, like this:
foreach(var Data in rMatrix)
{
RM.Column_Id = Data.Column_Id;
RM.ProMonSys_Right = Data.ProMonSys_Right;
RM.UserName = userNameToNew;
UpdateModel(RM);
context.AddObject("Right_Matrix", RM);
}
context.SaveChanges();
Obviously, those two context. calls would have to be made into methods on your repository, but you get the picture.

Related

How to get the ID of an inserted record in HANA back to SAPUI5 application?

I got an SAPUI5-application in which I create entries and save them via OData-service. That works, the code for the create operation can be found below. What I have to do now is, I need the ID of the inserted record in HANA back in my application. So what I did I implemented a success handler and thought I would get back this ID in the response from my OData-service. But that is not the case, I get back the same value I provided, in this case 0 since this just a dummy value for the OData-service. I did some research on how to tackle this problem, but none of the approaches worked. So I hope someone of you can help me out or got a hint how to do this. Below the code for create-operation, odata-service and the create.xsjs:
Create-operation in SAPUI5:
this.getOwnerComponent().getModel("Mitarbeiter").create("/ARB", oEntry, {
success: function(oData, response){
console.log(response);
}
});
OData-service:
service {
"MITARBEITERABTEILUNG"."ABTEILUNG" as "ABT" navigates ("Mitarbeiter" as "ARB");
"MITARBEITERABTEILUNG"."Mitarbeiter" as "ARB" create using "public.MitarbeiterAbteilung:mitarbeiterMethods.xsjslib::mitarbeiterCreate";
association "Mitarbeiter"
principal "ABT"("ID")
multiplicity "1"
dependent "ARB"("Abteilung")
multiplicity "*";
}
Create.xsjs:
function mitarbeiterCreate(param) {
let aAfterTableName = param.afterTableName;
var oEntry = {};
try {
var statement = param.connection.prepareStatement("SELECT * FROM\"" + aAfterTableName + "\"");
var rs = statement.executeQuery();
var statement2 = param.connection.prepareStatement('SELECT "MITARBEITERABTEILUNG"."MASEQUENCE".NEXTVAL from dummy');
var rs2 = statement2.executeQuery();
while (rs2.next()) {
oEntry.ID = rs2.getInteger(1);
}
statement2.close();
while (rs.next()) {
oEntry.Name = rs.getString(2);
oEntry.Adresse = rs.getString(3);
oEntry.bz = rs.getString(4);
oEntry.Abteilung = rs.getInteger(5);
}
statement = param.connection.prepareStatement('INSERT INTO "MITARBEITERABTEILUNG"."Mitarbeiter" VALUES (?,?,?,?,?)');
statement.setInteger(1, oEntry.ID);
statement.setString(2, oEntry.Name);
statement.setString(3, oEntry.Adresse);
statement.setString(4, oEntry.bz);
statement.setInteger(5, oEntry.Abteilung);
statement.execute();
statement.close();
} catch (e) {
statement.close();
}
}
Answered in the SAP Community here: https://answers.sap.com/questions/566957/how-to-get-the-id-of-an-inserted-record-in-hana-ba.html
The only thing you need to do, is to update the ID value in the "afterTableName" table provided by the function parameter. Something like that:
let statement = param.connection.prepareStatement('update "' + param.afterTableName + '" set ID = ' + oEntry.ID);
statement.executeUpdate();
Of course that needs to be done after you have determined your new ID. In case your column name is not "ID", please replace it with the real column name.

"CS0162: Warning as Error: Unreachable code detected" on Razor View

I have the following code within a script tag on my razor view:
self.regions = [];
#foreach(var region in Model.OperationRegions)
{
<text>
self.regions.push({
regionid: '#region.Region_Id',
regionname: '#region.Title',
selected: ko.observable(#(Model.RegionsList.Contains(region.Region_Id).ToString().ToLower()))
});
</text>
}
self.categories = [];
#foreach(var category in Model.Categories)
{
<text>
self.categories.push({
categoryid: '#category.Category_Id',
title: '#category.Title'
});
</text>
}
For clarity, the code outside of the foreach loops and within the text tags are Javascript and the purpose of the razor code is to populate my Javascript arrays with data from the server.
When I run this I am currently getting a server error saying "CS0162: Warning as Error: Unreachable code detected"
The error is thrown on the second "foreach" in the snippet.
Surprisingly I couldn't find another question referring to this error message on an MVC razor page so I'm posting this here.
My question is why is that line of code considered to be unreachable? I will update this question if I find anything else on my page to be relevant to the issue as I try to debug.
The error has disappeared now. I had renamed a property of my model and not recompiled before trying to load the page again. Recompiling made the error go away. I have no idea how the root cause translated to the error message shown but its fixed now in any case.
This is an extremely poor way to handle this. There's no need to build an array piece by piece like this. Just convert your list to JSON.
self.regions = #Html.Raw(Json.Encode(Model.OperationRegions.Select(region => new {
regionid = region.Region_Id,
regionname = region.Title,
selected = Model.RegionsList.Contains(region.Region_Id)
})));
The only thing this can't handle is making selected an observable. However, you can simply loop through the array and fix this:
for (var i = 0; i < self.regions.length; i++) {
self.regions[i].selected = ko.observable(self.regions[i].selected);
}
However, the better approach is to use another view model:
var OperationRegionViewModel = function (data) {
var self = {};
self.regionid = ko.observable(data.regionid);
self.regionname = ko.observable(data.regionname);
self.selected = ko.observable(data.selected);
return self;
};
Then, you can just do something like:
var regions = #Html.Raw(Json.Encode(Model.OperationRegions.Select(region => new {
regionid = region.Region_Id,
regionname = region.Title,
selected = Model.RegionsList.Contains(region.Region_Id)
})));
self.regions = $.map(regions, new OperationRegionViewModel);
Or, even better build your JSON all at once:
var json = #Html.Raw(Json.Encode(new {
regions = Model.OperationRegions.Select(r => new { ... }),
categories = Model.Categories.Select(c => new { ... }),
// etc
});
Then, inject this all into your view model:
var viewModel = (function (json) {
// other stuff
self.regions = $.map(json.regions, new OperationRegionViewModel);
self.categories = $.map(json.categories, new CategoryViewModel);
// etc
})(json);

Entity Framework 5 - read a record then delete it in loop

I am having issues with my application. I have a db table for a print queue. When I read from that table in a loop, once I add that record to the view model, I then want to delete it from the database...this would be the most efficient way to do it, but EF barks:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
I've tried using multiple contexts... but that didn't seem to work either. I've seen articles like Rick Strahl's, but frankly it was above my level of understanding, and not exactly sure if it helps my issue here and seemed quite an in depth solution for something as simple as this.
Is there a simple way to accomplish what I am trying to achieve here?
Here is my code:
public List<InventoryContainerLabelViewModel> CreateLabelsViewModel(int intFacilityId)
{
var printqRep = new Repository<InventoryContainerPrintQueue>(new InventoryMgmtContext());
var printqRepDelete = new Repository<InventoryContainerPrintQueue>(new InventoryMgmtContext());
IQueryable<InventoryContainerPrintQueue> labels =
printqRep.SearchFor(x => x.FacilityId == intFacilityId);
List<InventoryContainerLabelViewModel> labelsViewModel = new List<InventoryContainerLabelViewModel>();
if (labels.Count() > 0)
{
//Get printq record
foreach (InventoryContainerPrintQueue label in labels)
{
IEnumerable<InventoryContainerDetail> icDtls =
label.InventoryContainerHeader.InventoryContainerDetails;
//Get print details
foreach (InventoryContainerDetail icDtl in icDtls)
{
labelsViewModel.Add(new InventoryContainerLabelViewModel()
{
...
populate view model here
}
);//Add label to view model
} //for each IC detail
//Delete the printq record
printqRepDelete.Delete(label); <======== Error Here
} //foreach label loop
}//label count > 0
return labelsViewModel.ToList();
}
In the end, I added a column to the printq table for status, then in the the loop updated it to processed, then called a separate method to delete it.
public List<InventoryContainerLabelViewModel> CreateLabelsViewModel(int intFacilityId)
{
InventoryMgmtContext dbContext = new InventoryMgmtContext();
var printqRep = new Repository<InventoryContainerPrintQueue>(dbContext);
IEnumerable<InventoryContainerPrintQueue> unprintedPrtqRecs =
printqRep.SearchFor(x => x.FacilityId == intFacilityId && x.Printed == false);
List<InventoryContainerLabelViewModel> labelsViewModel = new List<InventoryContainerLabelViewModel>();
if (unprintedPrtqRecs.Count() > 0)
{
//Get printq record
foreach (InventoryContainerPrintQueue unprintedPrtqRec in unprintedPrtqRecs)
{
IEnumerable<InventoryContainerDetail> icDtls =
unprintedPrtqRec.InventoryContainerHeader.InventoryContainerDetails;
//Get container details to print
foreach (InventoryContainerDetail icDtl in icDtls)
{
labelsViewModel.Add(new InventoryContainerLabelViewModel()
{
...
}
);//Get IC details and create view model
} //for each IC detail
unprintedPrtqRec.Printed = true;
printqRep.Update(unprintedPrtqRec, unprintedPrtqRec, false);
} //foreach label loop
//Commit updated to Printed status to db
dbContext.SaveChanges();
}//label count > 0
return labelsViewModel;
}
public ActionConfirmation<int> DeletePrintQRecs(int intFacilityId)
{
InventoryMgmtContext dbContext = new InventoryMgmtContext();
var printqRep = new Repository<InventoryContainerPrintQueue>(dbContext);
IEnumerable<InventoryContainerPrintQueue> printedPrtqRecs =
printqRep.SearchFor(x => x.FacilityId == intFacilityId && x.Printed == true);
foreach (InventoryContainerPrintQueue printedPrtqRec in printedPrtqRecs)
{
//Delete the printq record
printqRep.Delete(printedPrtqRec, false);
}
//Save Changes on all deletes
ActionConfirmation<int> result;
try
{
dbContext.SaveChanges();
result = ActionConfirmation<int>.CreateSuccessConfirmation(
"All Label Print Q records deleted successfully.",
1);
}
catch (Exception ex)
{
result = ActionConfirmation<int>.CreateFailureConfirmation(
string.Format("An error occured attempting to {0}. The error was: {2}.",
"delete Label Print Q records",
ex.Message),
1
);
}
return result;
}

Entity Framework 5 installation verification

I have an ASP.NET MVC 3 project using .NET framework 4.0 and LINQ to SQL. Because I have serious problems of performance with some queries the first time they are executed I decided to use Entity Framework 5 in order to take advantage of the new LINQ auto compiled feature.
Now I have installed VS 2012, .NET framework 4.5 and Entity Framework 5 and changed my project to point to the .NET framework 4.5 as well as updated my Data Context file to use EF5. The queries now have exactly the same performance, some of them are so slow at the first time execution that even I get a time out exception, the second time everything is fine, I am wondering if the problem is that maybe the migration process was not correct and I am using still the EF4 or it is just a problem of my query construction which can't use the auto compiled feature for an unknown reason.
The EntityFramework dll has the 5.0 version, and the System.Data.Entity dll the version 4, that is right, isn't? Any suggestions?
I include the most problematic query, it retrieves paginated the result for a grid (Telerik MVC grid) which I need to build through 2 queries (originally was a SQL sentence with a sub query):
/// <summary>
/// Get the elements for the AppLog grid.
/// </summary>
public void GetAppLogElements(
int clientID, string language, int functionID, int errorLevel,
int numPage, int pageSize, IList<IFilterDescriptor> filterDescriptors, IList<SortDescriptor> sortDescriptors, IList<GroupDescriptor> groupDescriptors,
ref IQueryable<Model_AppLog> rows, ref int numRows)
{
string orderString = string.Empty;
var items =
from ap in objDataContext.applicationLogs
where
ap.clientID == clientID &&
ap.recordGroup != null
join alf in objDataContext.appLogFunctions on
new { functionID = ap.functionID.Value } equals new { functionID = alf.functionID }
join ale in objDataContext.appLogErrorLevels on
new { errorLevel = ap.errorLevel.Value } equals new { errorLevel = ale.errorLevelID }
join als in objDataContext.appLogSeverities on
new { severity = ap.severity.Value } equals new { severity = als.severityID }
group new { ap, alf, als } by new { ap.functionID, ap.recordGroup, ap.clerkID } into queryGrouped
select new Model_AppLog()
{
sequence = queryGrouped.Max(c => c.ap.sequence),
functionID = queryGrouped.Key.functionID,
recordGroup = queryGrouped.Key.recordGroup,
clerkID = queryGrouped.Key.clerkID,
date = queryGrouped.Min(c => c.ap.date),
errorLevel = (queryGrouped.Max(c => c.ap.errorLevel) == null || !queryGrouped.Max(c => c.ap.errorLevel).HasValue ? 0 : queryGrouped.Max(c => c.ap.errorLevel)),
severity = queryGrouped.Max(c => c.ap.severity)
};
if (errorLevel != -1)
items = items.Where(column => column.errorLevel >= errorLevel);
var _items =
from subSelect in items
join alf in objDataContext.appLogFunctions on
new { functionID = subSelect.functionID.Value } equals new { functionID = alf.functionID }
join alft in objDataContext.appLogFunctionTexts on
new { alf.functionID, language } equals new { alft.functionID, alft.language }
join ale in objDataContext.appLogErrorLevels on
new { errorLevel = subSelect.errorLevel.Value } equals new { errorLevel = ale.errorLevelID }
join alet in objDataContext.appLogErrorLevelTexts on
new { errorLevelID = subSelect.errorLevel.Value, language } equals new { alet.errorLevelID, alet.language }
join als in objDataContext.appLogSeverities on
new { severity = subSelect.severity.Value } equals new { severity = als.severityID }
join alst in objDataContext.appLogSeverityTexts on
new { als.severityID, language } equals new { alst.severityID, alst.language }
select new Model_AppLog()
{
sequence = subSelect.sequence,
functionID = subSelect.functionID,
recordGroup = subSelect.recordGroup,
clerkID = subSelect.clerkID,
date = subSelect.date,
errorLevel = subSelect.errorLevel,
severity = subSelect.severity,
functionDescription = alft.denotation,
errorLevelDescription = alet.denotation,
severityDescription = alst.denotation
};
//Apply filters
if (filterDescriptors != null && filterDescriptors.Any())
{
_items = _items.Where(ExpressionBuilder.Expression<Model_AppLog>(filterDescriptors));
}
if (functionID != -1)
_items = _items.Where(column => column.functionID == functionID);
//Apply sorting
if (sortDescriptors != null)
{
GlobalMethods objGlobalMethods = new GlobalMethods();
orderString = objGlobalMethods.GetOrderString(sortDescriptors);
}
//Apply ordering
if (orderString != string.Empty)
_items = _items.OrderBy(orderString);
else
_items = _items.OrderByDescending(x => x.date);
//Set total number of rows
numRows = _items.AsEnumerable<Model_AppLog>().Count();
//Get paginated results
_items = _items.Skip(pageSize * (numPage - 1)).Take(pageSize);
//Set data result
rows = _items;
}
Here's a paper about EF performance: MSDN
The most important thing you can do to improve start up time is to precompile your views ( there's a section near the end of the MSDN paper )
If you're using database first, there's a T4 template here you can use.
If you're using code first, there's a project here, although I haven't tried it myself.
Note: when you upgrade your project from .NET 4.0 to .NET 4.5, you have to uninstall the EF NuGet package and reinstall it - there are different version of EF 5 for the different runtimes.

OData Service not returning complete response

I am reading Sharepoint list data (>20000 entries) using Odata RESTful service as detailed here -http://blogs.msdn.com/b/ericwhite/archive/2010/12/09/getting-started-using-the-odata-rest-api-to-query-a-sharepoint-list.aspx
I am able to read data but I get only the first 1000 records. I also checked that List View Throttling is set to 5000 on sharepoint server. Kindly advise.
Update:
#Turker: Your answer is spot on!! Thank you very much. I was able to get the first 2000 records in first iteration. However, I am getting the same records in each iteration of while loop. My code is as follows-
...initial code...
int skipCount =0;
while (((QueryOperationResponse)query).GetContinuation() != null)
{
//query for the next partial set of customers
query = dc.Execute<CATrackingItem>(
((QueryOperationResponse)query).GetContinuation().NextLinkUri
);
//Add the next set of customers to the full list
caList.AddRange(query.ToList());
var results = from d in caList.Skip(skipCount)
select new
{
Actionable = Actionable,
}; Created = d.Created,
foreach (var res in results)
{
structListColumns.Actionable = res.Actionable;
structListColumns.Created= res.Created;
}
skipCount = caList.Count;
}//Close of while loop
Do you see a <link rel="next"> element at the end of the feed?
For example, if you look at
http://services.odata.org/Northwind/Northwind.svc/Customers/
you will see
<link rel="next" href="http://services.odata.org/Northwind/Northwind.svc/Customers/?$skiptoken='ERNSH'" />
at the end of the feed which means the service is implementing server side paging and you need to send the
http://services.odata.org/Northwind/Northwind.svc/Customers/?$skiptoken='ERNSH'
query to get the next set of results.
I don't see anything particularly wrong with your code. You can try to dump the URLs beign requested (either from the code, or using something like fiddler) to see if the client really sends the same queries (and thus getting same responses).
In any case, here is a sample code which does work (using the sample service):
DataServiceContext ctx = new DataServiceContext(new Uri("http://services.odata.org/Northwind/Northwind.svc"));
QueryOperationResponse<Customer> response = (QueryOperationResponse<Customer>)ctx.CreateQuery<Customer>("Customers").Execute();
do
{
foreach (Customer c in response)
{
Console.WriteLine(c.CustomerID);
}
DataServiceQueryContinuation<Customer> continuation = response.GetContinuation();
if (continuation != null)
{
response = ctx.Execute(continuation);
}
else
{
response = null;
}
} while (response != null);
I had the same problem, and wanted it to be a generic solution.
So I've extended DataServiceContext with a GetAlltems methode.
public static List<T> GetAlltems<T>(this DataServiceContext context)
{
return context.GetAlltems<T>(null);
}
public static List<T> GetAlltems<T>(this DataServiceContext context, IQueryable<T> queryable)
{
List<T> allItems = new List<T>();
DataServiceQueryContinuation<T> token = null;
EntitySetAttribute attr = (EntitySetAttribute)typeof(T).GetCustomAttributes(typeof(EntitySetAttribute), false).First();
// Execute the query for all customers and get the response object.
DataServiceQuery<T> query = null;
if (queryable == null)
{
query = context.CreateQuery<T>(attr.EntitySet);
}
else
{
query = (DataServiceQuery<T>) queryable;
}
QueryOperationResponse<T> response = query.Execute() as QueryOperationResponse<T>;
// With a paged response from the service, use a do...while loop
// to enumerate the results before getting the next link.
do
{
// If nextLink is not null, then there is a new page to load.
if (token != null)
{
// Load the new page from the next link URI.
response = context.Execute<T>(token);
}
allItems.AddRange(response);
}
// Get the next link, and continue while there is a next link.
while ((token = response.GetContinuation()) != null);
return allItems;
}

Resources