I'm building a page within an MVC application that contains a drop down box that allows the user to select a from a number of financial periods.
For the purposes of making it clearer for our users, I'd like to append "(Current)" to the option that is the current financial period and potentially "(Latest)" to the previous period to represent the last full period. We can already determine which financial period we are in and subsequently the one previous and so on.
So let's say the two options I'm looking to append to currently look like this:
Period 11
Period 12
and I'd like it them to read:
Period 11 (Latest)
Period 12 (Current)
The drop down is populated from a database, but I would like to append this text at the application level.
Is this something that is possible? If so, how? I'm at a bit of a loss as to how to go about it.
Thanks for any help in advance.
I assume you're using some sort of IEnumerable on your model/view model class to populate the items in the drop-down. When you construct this list, simply add your "(Current)" and "(Latest)" options before returning the model to your view. If FinancialPeriod is a model/view model class like this:
public class FinancialPeriod{
public int FinancialPeriodId { get; set; }
public string DisplayText { get; set; }
}
Then you could do this in your controller, assuming that your list of all Financial Periods retrieved from the database is a property on your model called FinancialPeriods:
public ActionResult Index(){
var model = GetTheModel();
model.FinancialPeriods.Add(new FinancialPeriod{
FinancialPeriodId = <something>,
DisplayText = "(Current)"
};
model.FinancialPeriods.Add(new FinancialPeriod{
FinancialPeriodId = <somethingElse>
DisplayText = "(Latest)"
};
return View(model);
}
Make sure you substitute values for <something> and <somethingElse> that you can interpret correctly when the model is posted back to your controller.
Edit - based on your comments and edits, something like this is more appropriate:
public ActionResult Index(){
var model = GetTheModel();
var currentMonth = DateTime.Now.Month;
var previousMonth = currentMonth - 1;
if (previousMonth == 0)
previousMonth = 12;
var currentPeriod = "Period " + currentMonth.ToString();
var latestPeriod = "Period " + previousMonth.ToString();
var newList = new List<FinancialPeriod>();
foreach(var period in model.FinancialPeriods){
if(period.DisplayText == currentPeriod)
{
newList.Add(new FinancialPeriod
{
FinancialPeriodId = period.FinancialPeriodId,
DisplayText = period.DisplayText + " (Current)"
};
continue;
}
if(period.DisplayText == latestPeriod)
{
newList.Add(new FinancialPeriod
{
FinancialPeriodId = period.FinancialPeriodId,
DisplayText = period.DisplayText + " (Latest)"
};
continue;
}
newList.Add(period);
}
model.FinancialPeriods = newList;
return View(model);
}
Related
I posted the question earlier, but didn't receive any correct responses, hence posting again with some edits. I have a function that accepts two parameters, IDs and Dates. When I had put breakpoints, I was able to see the Ids and the Dates selected on the page as parameter values. However, after hitting the process button, nothing happens, meaning this data isn't getting saved to the DB.
Model Classes:
public class Hello{
public string ID{ get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime? Date{ get; set; }
}
Controller Class:
[HttpGet]
public ActionResult Selection(string ids, string dates)
{
model = new Hello();
ExtensionDB db = new ExtensionDB();
string[] IDS = ids.Split(',');
string[] DATES = dates.Split(',');
List<Hello> list = new List<Hello>();
for (int i = 0; i < IDS.Length; i++)
{
if (IDS[i] != null && IDS[i] != "")
{
Hello item = new Hello { ID = IDS[i], Date = DateTime.Parse(DATES[i]) };
list.Add(item);
}
}
if (ModelState.IsValid)
{
foreach (var row in db.Table1)
{
foreach (var row2 in db.Table2)
{
if (row.UID== row2.CID) // UID and CID are Foreign keys that join these two tables
{
foreach (var item in list)
{
if (row.UID == Convert.ToInt32(item.ID))
{
row2.ReportedDate = item.Date;
}
db.SaveChanges();
}
}
}
}
ViewBag.Message = "Success";
return View(model);
}
else
{
ViewBag.Message = "Failed";
return View(model);
}
}
I will add the view class if needed, however the problem is here.. You can also refer to it here: Saving changes to the DB MVC
Your code does not attempt to update anything. Start with confirming what the data you are passing to this POST call contains, and what you want to do with it. It looks like what you are trying to do is update the dates for a number of records. Looking at your previous post (no need to re-post another question with the same code) there are a few things..
First: Structure the data you want to pass to the POST call into a collection of simple objects containing an id and a date. For example:
{
id = rid,
date = date
}
and add those to the collection named something like "updateData" rather than two separate arrays of IDs and dates. Then in the server-side code, declare a simple view model class:
public class UpdateDateViewModel
{
public int Id { get; set; }
public DateTime Date { get; set; }
}
In the ajax call instead of:
data: { ids: ids, dates: dates },
you'll want something like:
data: { updates: updateData },
where updateData is your collection of id + date pairs.
and use that view model in your method:
public ActionResult Process(IList updates)
Provided that request data is sent as Json, ASP.Net should translate that data automatically for you, though you may need to configure ASP.Net to translate the camelCase vs PascalCase. Worst case, to test, you can use camelCase property names ("id" and "date")
Now when it comes to updating the data: Server side, please get in the habit of using meaningful variable names, not "c", "i", etc. It makes code a lot easier to understand.
public ActionResult Process(IList<UpdateDateViewModel> updates)
{
using (db = new DB())
{
//rp = new RequestProcess(); - Assuming RequestProcess is an Entity?
//var c = rp.getStuff(); - No idea what this getStuff() method does...
foreach(var update in updates)
{
var request = db.RequestProcesses.Find(update.Id);
if (request != null)
request.RequestDate = update.Date; // If we find a matching request, update it's date.
else
{ // Doesn't exist, create it and add it to the DbSet.(table)
var request = new RequestProcess { Id = update.Id, RequestDate = update.Date };
db.RequestProcesses.Add(request);
}
db.SaveChanges();
}
}
}
Now this is a very bare bones guess at what you may be trying to do. Ideally though, updates should be completely separate from adds in the sense that an update should only deal with existing records. If it comes across an ID that it cannot find it should throw an error, ignore, and/or return a status to the user that something wasn't right. Creating new entries should be a separate call and ensure that records are properly initialized with their required fields.
Your original code looked to be taking a list of IDs, but then creating a new entity and calling that "getStuff" method that didn't have the DbContext, or any of the values from the POST call, but then attempting to copy values from that entity into the string parameters that you passed (which would overwrite the Json string) None of that would have updated an entity which would never have updated your data.
Take it slow and follow the examples before attempting to adapt them to your ideas. It will be a lot more constructive and less frustrating then writing a bunch of code that doesn't really make much sense, then wondering why it doesn't work. Your original code has probably a dozen or more problems and inefficiencies. Simply pasting it up on Stack will get a lot of confusing comments based on these problems which don't really help with the first issue you want to solve. Strip it back to the minimum, start with getting the data you need to the server in a meaningful way, then from that, attempt to use that data to update your entities.
I'm trying to update a value in an existing row of a database but I can't seem to get the changes to stick. the code in my controller currently looks like this:
[HttpPost]
public ActionResult AddCredit(int employeeNumber, decimal amount)
{
var employee = new GetEmployeeForEmployeeNumber<Employee>(employeeNumber).Query().FirstOrDefault();
var employeeAccount = new GetEmployeeAccountForId<EmployeeAccount>(employee.Id).Query().FirstOrDefault();
employeeAccount.Credit = employeeAccount.Credit + amount;
db.SaveChanges();
return RedirectToAction("Home", new { employeeNumber });
}
Based on research that I've done into the subject, this should work as I've modelled it off working example. The Credit does increase by the given amount but after the db.SaveChanges, the values in the database are still as they were.
Am I missing something obvious?
Edit:
The GetEmployeeAccountForId looks like this:
public class GetEmployeeAccountForId<T>
{
private TestContext db = new TestContext();
private readonly int _id;
public GetEmployeeAccountForId(int id)
{
_id = id;
}
public IQueryable<EmployeeAccount> Query()
{
return from employeeAcount in db.EmployeeAccounts
where employeeAcount.Id == _id
select employeeAcount;
}
}
Try this:
employeeAccount.Credit = employeeAccount.Credit + amount;
db.Entry(employeeAccount).State = EntityState.Modified;
db.SaveChanges();
Update
You have to "tell" EF to track changes of editet entity, that's why
db.Entry(employeeAccount).State = EntityState.Modified
is required.
But You also shoudn't use 2 different instances of one DbContext. I highly recomend using DI, and set DbContext life time to instance per request.
The project I am working is 'University Management System' and it's a big one. Right now, I am implementing the student registration section that works fine (A small portion of the project). I've used 'Three-Tier Architecture' and 'ORM - EF' in ASP.NET MVC template. In the project, I need to do some validations for registering students depending upon their year, department etc. So there are sections like DAL, BLL, finally controller and view. I've done the validations in the controller and getting the data from BLL that again retrieves data from DAL (This is the simple condition of 'Three-Tier Architecture'). So my questions are:
1) Is it OK to do the validations in the controller?
2) If not and need to do it in the BLL, will it be just fine and why or I can
continue doing it in the controller?
Note: To me, doing the validations in the controller or BLL seems OK and the same. Does it have any effect?
Right now, I've done the following:
DAL:
public List<Student> Add(int studentID, string studentName, string email, DateTime regDate)
{
List<Student> lst = null;
Student aStudent = new Student();
aStudent.StudentID = studentID;
aStudent.StudentName = studentName;
aStudent.Email = email;
aStudent.RegDate = regDate;
try
{
db.Students.Add(aStudent);
db.SaveChanges();
}
catch (Exception ex)
{
ex.ToString();
}
return lst;
}
BLL:
public List<Student> Add(int studentID, string studentName, string email, DateTime regDate)
{
return aStudentGateway.Add(studentID, studentName, email, regDate);
}
Controller:
/**Student Registration - Starts**/
[HttpPost]
public ActionResult AddStudent(Student aStudent)
{
List<Department> departments = aDepartmentManager.GetAllDepartments();
List<DepartmentViewModel> departmentsViewModel = aDepartmentManager.GetAllDepartmentViewModel();
DateTime yearInDateTime = Convert.ToDateTime(Request.Form["RegDate"]);
string extractYear = yearInDateTime.ToString();
var year = DateTime.Parse(extractYear).Year;
int department = Convert.ToInt32(Request.Form["Department"]);
List<Student> studentList = aStudentManager.GetAllStudents();
int count = 1;
var query = (from c in studentList
where c.Department == department && c.Year == year
select c).ToList();
foreach (var c in query)
{
if (query.Count() > 0)
{
int m = Convert.ToInt32(c.StudentID);
count = m + 1; //Incrementing the numbers by one with the table column
}
else
{
int m = 1;
count = m + 1; //Incrementing the numbers by one with the variable assigned one
}
}
Student student = new Student();
student.StudentName = Request.Form["StudentName"];
student.Email = Request.Form["Email"];
student.RegDate = Convert.ToDateTime(Request.Form["RegDate"]);
student.StudentID = count;
if (aStudentManager.ExistEmailAny(student.Email))
{
ViewBag.ErrorMessage = "Email already exists";
}
else
{
aStudentManager.Add(aStudent.StudentID, aStudent.StudentName, aStudent.Email, aStudent.RegDate);
ViewBag.Message = "Registration successful. See below to verify.";
/**This section used to show student details after registration**/
var result = (from c in departments
join d in departmentsViewModel on c.DepartmentID equals d.DepartmentId
where d.DepartmentId == department
select c);
foreach (var items in result)
{
if (count.ToString().Length > 1)
{
ViewBag.StudentID = items.Code + "-" + year + "-" + "0" + count;
}
else
{
ViewBag.StudentID = items.Code + "-" + year + "-" + "00" + count;
}
StudentViewModel.StudentID = student.StudentID;
StudentViewModel.StudentName = student.StudentName;
StudentViewModel.Email = student.Email;
StudentViewModel.RegDate = student.RegDate;
}
/**This section used to show student details after registration**/
}
return View();
}
/**Student Registration - Ends**/
I would provide multiple steps of validation in the different layers, depending on the context and the meaning of the layer.
First, it's a best practice to provide validation both on client and server side.
For the client side you should provide field checks for required fields and other simple validations. If you are using MVC you can use data annotations.
The same validation should be replicated in the controller. Here you should fail fast applying some kind of contract to the parameters that have been passed. One good practice is using Code Contracts that provide preconditions that need to be satisfied to go on in your pipeline of execution.
In the business layer provide the check that needs to be done in the business logic.
Finally in the data access layer provide all the checks that are needed to persist your data. If you are using EF a good practice is implementing the IValidatableObject for your entity classes. Here in Scott Gu's blog you can find a post that explains this technique.
Even though this approach look like it will introduce repetitions, it will provide consistency in your data and separate concerns between your layers.
1) Is it OK to do the validations in the controller?
No at all, it would be more better to use Data Annotation Validator Attributes, and to do validation in your model class.
Second thing, you're doing some stuff of DAL in your controller, like
List<Department> departments = aDepartmentManager.GetAllDepartments();
List<DepartmentViewModel> departmentsViewModel = aDepartmentManager.GetAllDepartmentViewModel();
var query = (from c in studentList
where c.Department == department && c.Year == year
select c).ToList();
These all queries should be in DAL, which is exact use of DAL to interact with the database, and keep your controller clean.
Third thing,
If you pass Student to the controller, then not need to get each attribute using Request.Form.
Hope this make sense!
I'm trying to do some sort of conditional statement to calculate a value. To mock my data I am assigning the value in my controller (temporarily) to see how my UI is coming along. I can perform the calculation in a function block in the view, but it's lengthy and doesn't belong there. So, I am trying now to do the calculation in a model (Calculations.cs).
The code for the calculation is working in that a value is being passed, except that my condition is failing and passing the default value of 0 when it should be passing another value based on my mocked value in the controller.
Here is the Calculations.cs
public class Calculations
{
PriceQuote price = new PriceQuote();
StepFilingInformation filing = new StepFilingInformation();
public decimal Chapter7Calculation
{
get
{
return
price.priceChapter7
+
((ReferenceEquals
(filing.PaymentPlanRadioButton,
Models.StepFilingInformation.PaymentPlan.Yes))
?
price.pricePaymentPlanChapter7
:
0);
}
}
}
I originally had (filing.PaymentPlanRadioButton == Models.StepFilingInformation.PaymentPlan.Yes) checking whether or not the radio button was set to "Yes", but changed it to ReferenceEquals. This doesn't affect the outcome.
I have my controller assigning the value to PaymentPlanRadioButton to "Yes", so pricePaymentPlanChapter7 should be the value being added to priceChapter7, but it is not. Instead "0" is being added as the fall back to the condition. So PaymentPlanRadioButton is null even though I am assigning it in the controller.
I cannot figure out how to fix this. If I assign it in the model and get it to work that will not resolve the issue as when I remove the mocking controller and expect a user to choose a radio button it will still be null and the condition will fail.
Here is the "mock" controller:
public class QuoteMailerController : Controller
{
public ActionResult EMailQuote()
{
Calculations calc = new Calculations();
var total = calc.Chapter7Calculation;
QuoteData quoteData = new QuoteData
{
StepFilingInformation = new Models.StepFilingInformation
{
//"No" is commented out, so "Yes" is assigned
//PaymentPlanRadioButton =
//Models.StepFilingInformation.PaymentPlan.No,
PaymentPlanRadioButton =
Models.StepFilingInformation.PaymentPlan.Yes,
}
};
}
}
And this is where I store prices (PriceQuote.cs):
public class PriceQuote
{
public decimal priceChapter7 { get { return 799; } }
public decimal pricePaymentPlanChapter7 { get { return 100; } }
}
This is my ViewModel:
public class QuoteData
{
public PriceQuote priceQuote;
public Calculations calculations;
public StepFilingInformation stepFilingInformation { get; set; }
public QuoteData()
{
PriceQuote = new PriceQuote();
Calculations = new Calculations();
}
}
So, the way this should work is 799 + 100 = 899, since PaymentPlan.Yes is assigned as the value to the radio button in the controller. But instead I am getting just 799 (799 + 0) because when I debug PaymentPlanRadioButton is coming up null.
Any thoughts/guidance?
Just in case, here is the PaymentPlanRadioButton located within StepFilingInformation.cs (and is one of my models):
public enum PaymentPlan
{
No,
Yes
}
public class PaymentPlanSelectorAttribute : SelectorAttribute
{
public override IEnumerable<SelectListItem> GetItems()
{
return Selector.GetItemsFromEnum<PaymentPlan>();
}
}
[PaymentPlanSelector(BulkSelectionThreshold = 3)]
public PaymentPlan? PaymentPlanRadioButton { get; set; }
Sorry for the length.
Your Calculations class bases it's math on the StepFilingInformation object it contains. However, you never set StepFilingInformation from within Calculations to anything other than a new, empty object.
Your constructor should probably require a parameter of type StepFilingInformation.
public class Calculations
{
StepFilingInformation filing;
public Calculations(StepFilingInformation filing)
{
this.filing = filing;
}
Regardless of how you pass your calculations class a reference to StepFilingInformation, you must set this value before you run your calculation that depends on it.
Also if QuoteData is your ViewModel, then it shouldn't contain a reference to your Calculations class. It should only contains results created in the calculations class that the View must display.
StepFilingInformation filing = new Models.StepFilingInformation
{
PaymentPlanRadioButton = Models.StepFilingInformation.PaymentPlan.Yes,
};
Calculations calc = new Calculations(filing);
var total = calc.Chapter7Calculation;
QuoteData quoteData = new QuoteData //Only include Properties you're going to display in the view model
{
Total = total
};
I have an MVC 3 appliation which I have many integer fields on a form. They all require range validation but the ranges exists in a table in my database. So I would like to create a reusable remote validation tool which will look up the min and max value and return the validation to the view.
I am updating this with some example code of what I would like to do to see my request might clarify what I am looking for:
In my validation class:
[Remote("CheckIntegerRange", "Validation", ErrorMessage = "Value outside of range")]
public object UW1_Web_Tension_SP { get; set; }
[Remote("CheckIntegerRange", "Validation", ErrorMessage = "Value outside of range")]
public object UW2_Web_Tension_SP { get; set; }
[Remote("CheckIntegerRange", "Validation", ErrorMessage = "Value outside of range")]
public object UW3_Web_Tension_SP { get; set; }
In my ValidationController I tried to create a function with multiple parameters but I dont think I can - however I think it shows what I am trying to do more clearly:
public class ValidationController : Controller
{
public JsonResult CheckIntegerRange(int integer, string EntityName, string AttributeName)
{
var result = false;
int MinInteger = 0;
int MaxInteger = 100;
//declare recipe entities
var context = new MadicoRecipeEntities();
//set sql statements and get description, etc from attributes view
var esqlIntegerAttributeDetails = "SELECT VALUE c FROM MadicoRecipeEntities.v_AttributeIntegerRangeDetails AS c " +
"WHERE c.EntityName = '" + EntityName + "' AND c.Attribute = '" + AttributeName + "'";
var queryAttributeDetails = context.CreateQuery<v_AttributeIntegerRangeDetails>(esqlIntegerAttributeDetails);
var RecipeAttributes = queryAttributeDetails.ToList();
foreach (var AttributeDetails in RecipeAttributes)
{
MinInteger = AttributeDetails.Min;
MaxInteger = AttributeDetails.Max;
}
return Json(result, JsonRequestBehavior.AllowGet);
}
}
I have found the following post on the asp.net forums which handled my first obstacle - passing different named attributes to the same validator. However, in this example the name is passed in generically - I need to have the name in order to query the table to get the applicable min and max ranges.
http://forums.asp.net/t/1625928.aspx/3/10
Can anyone point me in the right direction?
Thanks!
It is called remote validation! Here is an example:
remote validation