My Controller
public ActionResult Index()
{
TechnicianFacade _oTechFacade = new TechnicianFacade();
Maintenance_.Models.IndexModel _oTechModel = new Maintenance_.Models.IndexModel();
IList<Maintenance_.Models.IndexModel> _otechList = new List<Maintenance_.Models.IndexModel>();
var tech = _oTechFacade.getTechnicians("", _oAppSetting.ConnectionString).ToArray();
foreach (var test in tech)
{
string fName = test.GetType().GetProperty("FIRSTNAME").GetValue(test, null).ToString();
_oTechModel.firstName = fName;
_otechList.Add(_oTechModel); <===
}
_oTechModel.fNameList = _otechList;
return View("Index", _oTechModel);
}
In my controller: index, can get all data object from my database. But if I have more than one data object in my database the: _otechList.Add(_otechModel) will overwrite the first entry with the newly added data, like for example lets just say we have 2 object data: (FIRST loop of foreach) _otechList.Add(_oTechModel) has a data of "FIRSTNAME" = "GEM" where count = 0, (SECOND loop of foreach) _otechList.Add(_oTechModel) has a data of "FIRSTNAME" = "DIAMOND" where count = 1, this time the value of count[0] became "FIRSTNAME" = "DIAMOND" as well. Is there something missing in my code or there's something wrong on it?
It will replace because same object value is changed, you need to instantiate object inside foreach loop.
Maintenance_.Models.IndexModel _oTechModel = new Maintenance_.Models.IndexModel();
like this:
foreach (var test in tech)
{
string fName = test.GetType().GetProperty("FIRSTNAME").GetValue(test, null).ToString();
Maintenance_.Models.IndexModel _oTechModel = new Maintenance_.Models.IndexModel();
_oTechModel.firstName = fName;
_otechList.Add(_oTechModel);
}
your object is global so every time same object is added in the list, instantiate it inside foreach loop so that every time new object is added in the list.
Related
I'm fairly new at MVC and linq and viewmodels in particular. I managed to get a create and index views to work. The "insert" wasn't as hard as the "list".
I have this linq query:
public ActionResult Index()
{
List<BlendElVM> BEVM = new List<BlendElVM>();
var list = (from Blend in db.blends
join BlendEl in db.blendEl on Blend.ID equals BlendEl.ID
select new
{
Blend.ID, Blend.Title, Blend.TransDt, BlendEl.Comment
}).ToList();
foreach (var item in list)
{
BlendElVM o = new BlendElVM(); // ViewModel
o.Comment = item.Comment;
o.Title = item.Title;
o.TransDt = item.TransDt;
o.ID = item.ID;
BEVM.Add(o);
}
return View(BEVM);
}
What I'm not sure about is the "foreach" section. When I'm running in debug, the "list" shows up fine, but if I comment out the "foreach" I get an error - ie not expecting the model. What does the foreach do? It has to do with the database, but I don't understand the where it is using the "o" and setting the columns. I thought it would all be in one linq query. Is it possible to combine the two and eliminate the "foreach"?
var BEVM = (from blend in db.blends
join BlendEl in db.blendEl on Blend.ID equals BlendEl.ID
select new BlendELVM
{
ID = blend.ID,
Title = blend.Title,
TransDT = blend.TransDt,
comment = blendEl.Comment
}).ToList();
I believe that the foreach is needed in order to read every element in the object so in this case you have:
BlendElVM o = new BlendElVM();
So you're creating and object named " o " of the type BlendELVM and this object contains all the attributes that you declared before which are: ID, Title, TransDT, etc
When you put:
foreach (var item in list)
{
BlendElVM o = new BlendElVM(); // ViewModel
o.Comment = item.Comment;
o.Title = item.Title;
o.TransDt = item.TransDt;
o.ID = item.ID;
BEVM.Add(o);
}
You're assigning to the new object o the item that you're reading in the list and in the end adding it to the BVEM list and answering if you can combine them i will say no because at first you're declaring the query and then you're reading the items on the list and assining them to the BEVM list
Controller
foreach (DataRow temp in act.Rows)
{
_oResolutionModel.activityNo = temp["ActivityID"].ToString();
_oResolutionModel.assignTechnician = temp["TechNo"].ToString();
_oResolutionModel.recommendation = temp["RECOMMENDATION"].ToString();
_oResolutionModel.jobStart = (DateTime)temp["JobStart"];
_oResolutionModel.jobEnd = (DateTime)temp["JobEnd"];
_oResolutionFacade.setResolutionID(_oResolutionModel.activityNo);
DataTable res = _oResolutionFacade.getResolution(_oAppSetting.ConnectionString);
foreach (DataRow x in res.Rows)
{
_oResolutionModel.solution = x["Resolution"].ToString();
_oResolutionModel.remarks = x["Remarks"].ToString();
_oResolutionList.Add(_oResolutionModel);
break;
}
_oResolutionList.Add(_oResolutionModel);
break;
}
In here my _oResolutionList count = 1, meaning there's two data in it and it duplicated the first data. I want to have only 1 data in my _oResolutionList. Do I need to add some code in my inner Foreach or should I change something on it.?
Or You can suggest me how to delete the second data entry.?
Instead of using a foreach loop. You can also check the nullity first and then assign.
You can also do :
_oResolutionFacade.setResolutionID(_oResolutionModel.activityNo);
DataTable res = _oResolutionFacade.getResolution(_oAppSetting.ConnectionString);
_oResolutionModel.solution = res.Rows[0]["Resolution"].ToString() ?? string.Empty; //To make sure that if it is null it will assign to an empty string
_oResolutionModel.remarks = res.Rows[0]["Remarks"].ToString()?? string.Empty;
You have many solutions to deal with that.
Hope it will help you
I'm trying to create a list of orders in a custom Controller in a NopCommerce/MVC application and i want the list to be sorted by creationDate and contain total orders for that date and convert these values to string format.
The thing is i don't want an ActionResult displaying a grid in the view like in Admin/Orders. All i want is a List of all paid orders between model.StartDate and model.EndDate that contains two parameters "CreationDateUtc" and TotalOrders". i simply just need a list containing the data of orders sorted by creationdate.
The if i choose StartDate 2014-03-29 and EndDate 2014-04-02 the output i want would look something like this:
List OrdersTotalList with parameters CreationDateUtc and TotalOrders
CreationDateUtc "2014-03-29"
TotalOrders "562"
CreationDateUtc "2014-03-30"
TotalOrders "485"
CreationDateUtc "2014-03-31"
TotalOrders "733"
CreationDateUtc "2014-04-01"
TotalOrders "729"
CreationDateUtc "2014-04-02"
TotalOrders "681
"
I'm trying to access the data by an implementations of OrderList from OrderController in my CustomController. Problem is this method always returns 10 objects when infact the total number of orders within this timespace is 58. When debugging Total = orders.TotalCount are actually showing 58 orders as one int value). Also a gridmodel is used here but i really don't need a gridmodel, i just need the data from the database:
public List OrderList(GridCommand command, OrderListModel model, OrderModel Omodel)
{
DateTime S = new DateTime(2014, 3, 29); //-- Dates for testing
DateTime E = new DateTime(2014, 4, 02);
model.StartDate = S;
model.EndDate = E;
DateTime? startDateValue = (model.StartDate == null) ? null
: (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, _dateTimeHelper.CurrentTimeZone);
DateTime? endDateValue = (model.EndDate == null) ? null
: (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.EndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1);
OrderStatus? orderStatus = model.OrderStatusId > 0 ? (OrderStatus?)(model.OrderStatusId) : null;
PaymentStatus? paymentStatus = model.PaymentStatusId > 0 ? (PaymentStatus?)(model.PaymentStatusId) : null;
ShippingStatus? shippingStatus = model.ShippingStatusId > 0 ? (ShippingStatus?)(model.ShippingStatusId) : null;
//load orders
var orders = _orderService.SearchOrders(startDateValue, endDateValue, orderStatus,
paymentStatus, shippingStatus, model.CustomerEmail, model.OrderGuid, command.Page - 1, command.PageSize);
var gridModel = new GridModel<OrderModel>
{
Data = orders.Select(x =>
{
var customerCurrency = _currencyService.GetCurrencyByCode(x.CustomerCurrencyCode);
var totalInCustomerCurrency = _currencyService.ConvertCurrency(x.OrderTotal, x.CurrencyRate);
return new OrderModel()
{
Id = x.Id,
OrderTotal = _priceFormatter.FormatPrice(totalInCustomerCurrency, true, customerCurrency),
OrderStatus = x.OrderStatus.GetLocalizedEnum(_localizationService, _workContext),
PaymentStatus = x.PaymentStatus.GetLocalizedEnum(_localizationService, _workContext),
ShippingStatus = x.ShippingStatus.GetLocalizedEnum(_localizationService, _workContext),
CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc)
};
}),
Total = orders.TotalCount <-- Returns all orders (58) but as an integer
};
var reportSummary = _orderReportService.GetOrderAverageReportLine
(orderStatus, paymentStatus, shippingStatus, startDateValue, endDateValue, model.CustomerEmail);
var profit = _orderReportService.ProfitReport
(orderStatus, paymentStatus, shippingStatus, startDateValue, endDateValue, model.CustomerEmail);
var aggregator = new OrderModel()
{
aggregatorprofit = _priceFormatter.FormatPrice(profit, true, false),
aggregatortax = _priceFormatter.FormatPrice(reportSummary.SumTax, true, false),
aggregatortotal = _priceFormatter.FormatPrice(reportSummary.SumOrders, true, false)
//aggregatordates =
};
List<Order> TotalProductsSold = new List<Order>();
foreach (var o in orders)
{
TotalProductsSold.Add(o);
}
return TotalProductsSold.ToList(); //<-- returns 10 orders containing all order info
}
If i understand correct in order to archive this i have to first search through orders and if their PaymentStatus is Paid. Then create a List in the Method from above. A foreach loop could iterate through orders and add orders to the List, all though i need to specify i only want CreationDate and TotalOrders for that date as parameters in the List.
I know this isn't right but i emagine something similar. The thing is i need a list of order objects and not one object with one value:
List<OrderModel> OrdersTotalList = new List<OrderModel>();
foreach (var o in orders)
{
OrderModel OM = new OrderModel(OM.OrderTotal, OM.CreatedOn);
OrdersTotalList.Add(OM);
}
return OrdersTotalList; //--
Am i completely of or is this the right aproach? I was hoping someone more familiar with NopCommerce knows more about this.
Sorry for all the text
Thank you
Solved.
In order to get a full list of orders you can create a new constructor in IOrderService/OrderService that is of type List instead of IPagedList. The method used for searching orders are called "SearchOrders" and is of type IPagedList. IPagedList contains the property PageSize wich results in only 10 orders.
You can create a new method with same implementation as SearchOrders and change IPagedList to List, remove "int pageIndex" and "int pageSize".
Then use:
_orderService.YourNewConstructor(DateTime? startTime, DateTime? endTime,
OrderStatus? os, PaymentStatus? ps, ShippingStatus? ss, string billingEmail,
string orderGuid)
{
some code...
}
This will give you access to all orders.
Using ASP MVC5 and EF6.
I had a curious case the other day when I was looking to have different behaviour when a foreach-loop got to the last element.
The loop wouldn't enter if-condition comparing the object with the result from .Last()-method on the collection.
The collection I was iterating over was something like:
public class CollectionClass{
IEnumerable<TestClass1> CollectionA
IEnumerable<TestClass2> CollectionB
}
My code was something like:
DbContext db = new DbContext(); //just for illustration, not actual code
CollectionClass cc = new CollectionClass {
CollectionA = db.TestClasses1,
CollectionB = db.TestClasses2
};
//(TestClasses1 and TestClasses2 are DbSet<T> properties of my DbContext.
foreach(TestClass1 tc1 in cc.CollectionA)
{
if (tc1 == cc.CollectionA.Last()){ //<---NEVER enters in here!!
//doStuff
}
else{
//doOtherStuff
}
}
With the code above, the loop never entered into the if-condition, even for the last element, which one would expect.
But when changed my CollectionClass to:
public class CollectionClass{
List<TestClass1> CollectionA
List<TestClass2> CollectionB
}
and instantiated the CollectionClass-object like this:
CollectionClass cc = new CollectionClass {
CollectionA = db.TestClasses1.ToList(),
CollectionB = db.TestClasses2.ToList()
}; //Added .ToList()
the loop entered into the first if-condition at the last iteration as I expected.
Why this difference? Why did the equals-operator (==) evaluate to TRUE when the object had been stored in a List and FALSE when the object was stored in an IEnumerable?
I know that IEnumerable is an interface -- is that what makes the difference?
I even did an explicit test in the sorts of:
var obj1 = cc.CollectionA.Last();
var obj2 cc.CollectionA.Last();
bool result = obj1 == obj2; //result = FALSE
and the result was FALSE.
I think it's because in first example you get two objects from database. First from iteration and second from call to Last().
In second example all objects are created at the time you assign collections to CollectionA and CollectionB (you call ToList()).
It is because you are not allowed to use Last and LastOrDefault on DbSet objects. Instead you should use OrderByDescending(t=>t.ID).First()
The code below is updating the correct values into the OBJECT_TYPES table, but the OBJECT_ITEMS table is being overwritten but I am not sure why. Can anyone help?
var templateId = Request["id"].AsInt();
var dbcontext = new STDEntities1();
var query = dbcontext.OBJECT_TYPES.Where(o => o.ID == templateId);
var template = query.FirstOrDefault();
var newItem = new OBJECT_TYPES
{
CATEGORY_ID = template.CATEGORY_ID,
COMPANY_ID = template.COMPANY_ID,
OBJECT_NAME = "** Select A Name **",
HEIGHT = template.HEIGHT,
WIDTH = template.WIDTH,
TEMPLATE = template.ID
};
foreach (var field in template.OBJECT_ITEMS)
{
newItem.OBJECT_ITEMS.Add(field);
}
dbcontext.OBJECT_TYPES.Add(newItem);
dbcontext.SaveChanges();
this is happening because you are adding field which actually is an object that is being tracked by the dataContext/dbContext and even has an id. So the values are being overwritten.
Try creating the a new field OR try detaching the field from the context and then put the Id/Primary key to 0 and try inserting it again.