I am taking a prior question one step further (see this question), I am trying to figure out how to sum two (or more) selections the user makes with, for example, a radio button list. The selection the user makes is tied to an entity that contains a static currency value using if/else if statements.
These are the entities for price:
[DataType(DataType.Currency)]
[DisplayFormat(DataFormatString = "{0:c}")]
public decimal priceProcessingStandard = 0;
[DataType(DataType.Currency)]
[DisplayFormat(DataFormatString = "{0:c}")]
public decimal priceProcessingExpedited = 250;
[DataType(DataType.Currency)]
[DisplayFormat(DataFormatString = "{0:c}")]
public decimal priceSubmissionOnline = 0;
[DataType(DataType.Currency)]
[DisplayFormat(DataFormatString = "{0:c}")]
public decimal priceSubmissionManual = 200;
So, if I have two sets of if/else if statements such as:
#if (Model.ProcessingRadioButtons == Processing.Standard)
{
#Html.DisplayFor(m => m.priceProcessingStandard)
}
else if (Model.ProcessingRadioButtons == Processing.Expedited)
{
#Html.DisplayFor(m => m.priceProcessingExpedited)
}
...
#if (Model.SubmissionRadioButtons == Submission.Online)
{
#Html.DisplayFor(m => m.priceSubmissionOnline)
}
else if (Model.SubmissionRadioButtons == Submission.Manual)
{
#Html.DisplayFor(m => m.priceSubmissionManual)
}
and the user makes selections in the two separate radio button lists corresponding to Processing.Expedited and Submission.Manual, the code will respectively display $250.00 and $200.00.
I cannot, however, figure out how to sum those two to display $450.00. Bear in mind, I do not know the selections before hand, so doing priceProcessingExpedited + priceSubmissionManual in a function and then calling it will obviously not work. Also, I am doing about 10-15 of these but I only used two simple ones as an example of what I am trying to accomplish (so the fact that the other two choices are $0.00 doesn't mean anything because there are varying prices for other choices that I left out).
Any guidance?
UPDATE:
Based on suggestion in answer, I am doing this:
Model.calculated =
Model.priceSolution +
((Model.ProcessingRadioButtons == Processing.Standard) ?
Model.priceProcessingStandard :
(Model.ProcessingRadioButtons == Processing.Expedited) ?
Model.priceProcessingExpedited :
Model.priceProcessingUrgent);
Some notes:
priceSolution is a static value that I use as a base (it's the base value plus the user selections).
I am using calculated in the ViewModel and get; set;'ing it.
I left out the Namespace.ViewModels.MyData before Processing. for brevity.
I left out Submission for brevity as it's just a + then the same logic as in Processing.
You do know the selections before hand considering your #if (Model.SubmissionRadioButtions == Submission.Online) is a test against values currently held by the model - even if this is only after a POST.
As such, you should create a property in your view model that also performs these tests and sums the appropriate fields.
If you don't want this property displayed before the POST, make the property return a nullable type and wrap the view with #if(MySum.HasValue) { #Html.DisplayFor(m=>m.MySum) }
Related
I clearly don't know what I'm doing. This MVC stuff is really blowing my mind in trying to keep with the pattern. I've been following the MVC tutorials as well as mega-googling and this is the corner I've painted myself into.
I have multiple similar pieces of data I'm trying to get to a view. I'm able to get my code to work, but to me it just looks like it's going to be highly inefficient as we start pulling large recordsets from the db due to multiple calls to the db. So, I have a OrderSummary class, inside the class is this:
public IEnumerable<Order> GetOrders()
{
var orders = (from s in db.Orders
where s.UserId == uId
select s);
return orders.ToList();
}
Then this:
public decimal GetGrossProfitTotal()
{
var orders = (from s in db.Orders
where s.UserId == uId
select s);
decimal? grossprofittotal = orders.Sum(s => s.Profit);
return grossprofittotal ?? decimal.Zero;
}
So, if we take that last chunk of code and copy it for totalcommission and netprofittotal that's basically how I have things layed out. I would guess four calls to the db?
Then in the controller:
var ordersummary = new OrdersSummary();
var viewModel = new OrderSummary
{
Orders = ordersummary.GetOrders(),
GrossProfitTotal = ordersummary.GetGrossProfitTotal(),
CommissionTotal = ordersummary.GetCommissionTotal(),
NetProfitTotal = ordersummary.GetNetProfitTotal(),
};
return View(viewModel);
This gets me all the data I need in the view so I can work with it. To me, it just seems unnecessarily redundant and I'm guessing inefficient? If you throw in that I'm also doing sort and search parms, it's a lot of duplicate linq code as well. It seems like I should be able to do something to consolidate the data like this:
var orders = (from s in db.Orders
where s.UserId == uId
select s).ToList();
decimal grossprofittotal = orders.Sum(s => s.Profit);
decimal commissiontotal = orders.Sum(s => s.Commission);
decimal netprofittotal = orders.Sum(s => s.Profit + s.Commission);
and then wrap those four pieces of data (orders list, and three decimal values) up nicely in an array (or whatever) and send them to the controller/view. In the view I need to be able to loop through the orders list. Am I way off here? Or, what is standard procedure here with MVC? Thanks.
Yes, fetching the same data four times is indeed inefficient, and completely unneccesary. You can very well fetch it only once and then do the other operations on the data that you have.
You can keep the GetOrders method as it is if you like, but that's all the data that you need to fetch. If you fetch the data in the controller or in the model constructor is mostly a matter of taste. Personally I tend to put more logic in the model than the controller.
As long as you use ToList to make sure that you actually fetch the data (or any other method that realises the result as a collection), you can calculate the sums from what you have in memory. (Without it, you would still be doing four queries to the database.)
Instead of summing up the profit and commision from all items to get the net profit total, you can just calculate it from the other sums:
decimal netprofittotal = grossprofittotal + netprofittotal;
LinqToEntities tranlates all query into SQL. If you don't want to make more than one transaction, you can fetch the result into a variable by .ToList(),querying this object make the calculation by linqToObject in the memory.
Backward: It fetchs all orders from database first.
var ordersInMemory = orders.ToList();
decimal grossprofittotal = ordersInMemory.Sum(s => s.Profit);
decimal commissiontotal = ordersInMemory.Sum(s => s.Commission);
decimal netprofittotal = grossprofittotal + commissiontotal ;
I have a listview that I fill from an Adapter. My original code the data was being returned from a table, but now I need to get the code from a query with a join so the examples I used will no longer work and I haven't been able to find out how to use a query for this. I'm using an ORMrepository.
In my ORMrepository I have this function
public IList<Coe> GetmyCoe()
{
using (var database = new SQLiteConnection(_helper.WritableDatabase.Path))
{
string query = "SELECT Coe.Id, Adult.LName + ', ' + Adult.MName AS Name, Coe.Createdt FROM Adult INNER JOIN Coe ON Adult.CoeMID = Coe.Id";
return database.Query<Coe>(query);
}
}
which actually returns the data I want.
then in my Activity page I have this.
_list = FindViewById<ListView>(Resource.Id.List);
FindViewById<ListView>(Resource.Id.List).ItemClick += new System.EventHandler<ItemEventArgs>(CoeList_ItemClick);
var Coe = ((OmsisMobileApplication)Application).OmsisRepository.GetmyCoe();
_list.Adapter = new CoeListAdapter(this, Coe);
My Adapter page is where I have the problem, I know it is set up to to looking at a table which I'm not doing anymore. But I don't know how to change it for what I'm passing into it now. Current CoeListAdapter is:
public class CoeListAdapter : BaseAdapter
{
private IEnumerable<Coe> _Coe;
private Activity _context;
public CoeListAdapter(Activity context, IEnumerable<Coe> Coe)
{
_context = context;
_Coe = Coe;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var view = (convertView
?? _context.LayoutInflater.Inflate(
Resource.Layout.CoeListItem, parent, false)
) as LinearLayout;
var Coe = _Coe.ElementAt(position);
view.FindViewById<TextView>(Resource.Id.CoeMID).Text = Coe.Id.ToString();
//view.FindViewById<TextView>(Resource.Id.GrdnMaleName).Text = Coe.Name;
view.FindViewById<TextView>(Resource.Id.CreateDt).Text = Coe.CreateDt;
return view;
}
public override int Count
{
get { return _Coe.Count(); }
}
public Coe GetCoe(int position)
{
return _Coe.ElementAt(position);
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return position;
}
}
How do I set up the CoeListAdapter.cs page so that it can use the passed in data. As you can see I have a commented out lines where I fill a TextView which error because Coe.Name is not in the table model for Coe. but it is returned in the query. I believe my problem is IEnumerable but what do I change it to. I'm new to Mobile developement and suing VS2010 for Mono
The problem probably lies with the binding/mapping of the object not the creation of the view.
Or probably more specifically, the query.
Adult.LName + ', ' + Adult.MName AS Name
this should be:
Adult.LName || ', ' || Adult.MName AS Name
See also: String concatenation does not work in SQLite
From the sqlite docs: http://www.sqlite.org/lang_expr.html under the Operators heading:
The unary operator + is a no-op. It can be applied to strings,
numbers, blobs or NULL and it always returns a result with the same
value as the operand.
Note that there are two variations of the equals and not equals
operators. Equals can be either = or ==. The non-equals operator can
be either != or <>. The || operator is "concatenate" - it joins
together the two strings of its operands. The operator % outputs the
value of its left operand modulo its right operand.
The result of any binary operator is either a numeric value or NULL,
except for the || concatenation operator which always evaluates to
either NULL or a text value.
This shows that the + will evaluate to zero. If you use ||, the value will either be the correct value or NULL (if either of Adult.LName or Adult.MName is NULL).
This can be fixed by:
coalesce(first, '') || ', ' || coalesce(second, '')
but this may result in , LastName or FirstName,.
Another way would be to create another two properties in Coe called LName and MName.
Then bind the values to those properties and use the Name property like this:
public string Name
{
get { return string.Join(", ", LName, MName); }
}
This will probably be better as you can change how the Name appears especially if there are different combinations of First, Middle and Last names in different places.
And off topic:
I believe my problem is IEnumerable...
This is probably not too true as it returns the correct values. A better way would be to use IList as IEnumerable will iterate through the list each time to get the item as it does not know that the collection is actually a list. (I think)
thanks for the help on the concantination, I did find that was wrong, I did fix my problem, I was using an example by Greg Shackles on how to set up using a data base. what I had to do was create a new model with the elements I was wanting. So I created a new Model and called it CoeList, then everywhere I had List or IEnumerable I changed it to List or IEnumerable and it worked.
I'm sticking on how to best present some data that's being dynamically generated from two different tables.
Given my query:
var assets = assetRepo.Find(x => x.LoginId == User.Identity.Name);
var accounts = repository.Find(x => x.AccStatus == "A" && x.LoginId == User.Identity.Name);
var query = from asst in assets
join acct in accounts on asst.AccountId equals acct.AccountId
select new
{
Account = acct.AccountNumber,
Status = acct.AccStatus,
Make = asst.Make,
Model = asst.Model,
Submodel = asst.SubModel,
Registration = asst.Registration,
Balance = acct.BalanceOutstanding,
NextPayment = acct.NextPayment,
Date = String.Format("{0:dd MMM yyyy}", acct.NextPaymentDate),
Due = acct.ArrearsBal
};
What would be the best (i.e. cleanest) way to bind this to the view? Would a custom class be required or is there a way to specify and iterate over a collection of anonymous types?
Creating custom class can give you additional benefits. You can use DisplayAttribute to set column headers and order. Then you can create view (or template to use with DisplayFor) that takes list of objects of any type and uses reflection to read annotations and display view nicely.
class Report {
[Display(Name="Account",Order=1)]
public string Account {get; set;}
[Display(Name="Next payment",Order=2)]
public Date NextPayment {get; set;}
}
It looks also clean. You will be able to use this annotations not only for grid, but also for excel exports or other data operations.
how can you do multiple "group by's" in linq to sql?
Can you please show me in both linq query syntax and linq method syntax.
Thanks
Edit.
I am talking about multiple parameters say grouping by "sex" and "age".
Also I forgot to mention how would I say add up all the ages before I group them.
If i had this example how would I do this
Table Product
ProductId
ProductName
ProductQty
ProductPrice
Now imagine for whatever reason I had tons of rows each with the same ProductName, different ProductQty and ProductPrice.
How would I groupt hem up by Product Name and add together ProductQty and ProductPrice?
I know in this example it probably makes no sense why there would row after row with the same product name but in my database it makes sense(it is not products).
To group by multiple properties, you need to create a new object to group by:
var groupedResult = from person in db.People
group by new { person.Sex, person.Age } into personGroup
select new
{
personGroup.Key.Sex,
personGroup.Key.Age,
NumberInGroup = personGroup.Count()
}
Apologies, I didn't see your final edit. I may be misunderstanding, but if you sum the age, you can't group by it. You could group by sex, sum or average the age...but you couldn't group by sex and summed age at the same time in a single statement. It might be possible to use a nested LINQ query to get the summed or average age for any given sex...bit more complex though.
EDIT:
To solve your specific problem, it should be pretty simple and straightforward. You are grouping only by name, so the rest is elementary (example updated with service and concrete dto type):
class ProductInventoryInfo
{
public string Name { get; set; }
public decimal Total { get; set; }
}
class ProductService: IProductService
{
public IList<ProductInventoryInfo> GetProductInventory()
{
// ...
var groupedResult = from product in db.Products
group by product.ProductName into productGroup
select new ProductInventoryInfo
{
Name = productGroup.Key,
Total = productGroup.Sum(p => p.ProductCost * p.ProductQty)
}
return groupedResult.ToList();
}
}
I'm trying to use a SelectList one of my views, and its just not populating correctly. It gets the proper number of entries (4), but they all read System.Web.Mvc.SelectListItem. I fired up the debugger on the code, and saw some strangeness going on. I must be doing something wrong, but I don't quite see what.
Code from the ViewModel:
public SelectList DeviceTypes {get; private set;}
....
var device_types = DataTableHelpers.DeviceTypes();
IEnumerable<SelectListItem> sl = device_types.Select(
dt => new SelectListItem { Selected = (dt.DeviceType == 1),
Text = dt.Description,
Value = dt.DeviceType.ToString() }).ToList();
DeviceTypes = new SelectList(sl);
And code from the View:
<%= Html.DropDownList("Type",Model.DeviceTypes) %>
So, when I look at this in the debugger, the sl IEnumerable is getting built correctly. I can see all 4 elements in there, with the proper Text and Value property values. Once I call the SelectList constructor however, if I expand the IEnumerable that it contains, I see that it has 4 entries, but all the data in them has been lost. The Text is set to System.Web.Mvc.SelectListItem, and the value is null.
Ive tried changing the ToList() call to a ToArray(), as well as removing it entirely. That didn't change the behaviour.
What am I doing wrong here?
EDIT: Scratch my first answer.
You should be passing the IEnumerable list if items to the View, not trying to construct a Html item in the controller.
Code for controller:
public IEnumberable<YourModel> DeviceTypes {get; internal set;}
....
DeviceTypes = DataTableHelpers.DeviceTypes();
Code for View:
<%= Html.DropDownList("Type", from dt in Model.DeviceTypes
select new SelectListItem
{
Text = dt.Description,
Value = dt.DeviceType.ToString(),
Selected = dt.DeviceType == 1
}) %>