HI i have an MVC application which have CreatedDate and ModifiedDate feilds,
1. CreatedDate is when user create the module(any entry)
2. ModifiedDate is when user Edit the module
I have following Model class
namespace MyForms.Models
{
public class Master
{
public int ID { get; set; }
public string ModuleName { get; set; }
public int CreatedBy { get; set; }
public DateTime ? CreatedDate { get; set; }
public int ModifyBy { get; set; }
public DateTime ModifyDate { get; set; }
public Boolean IsActive { get; set; }
public Boolean IsDeleted { get; set; }
// public virtual ICollection<Master> MasterModules { get; set; }
}
public class MyFormDemoContext : DbContext
{
public DbSet<Master> MasterForms { get; set;}
}
}
Actions of Create and Edit
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Master master)
{
try
{
using (MyFormDemoContext context = new MyFormDemoContext())
{
master.CreatedBy = 1;
master.CreatedDate = DateTime.Now;
var a = master.CreatedDate;
master.IsActive = true;
master.ModifyBy = 1;
master.ModifyDate = DateTime.Now;
master.IsDeleted = false;
context.MasterForms.Add(master);
context.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
public ActionResult Edit(int id)
{
using (MyFormDemoContext context = new MyFormDemoContext())
{
return View(context.MasterForms.Find(id));
}
}
//
// POST: /Home/Edit/5
[HttpPost]
public ActionResult Edit(int id, Master valpara)
{
try
{
using (MyFormDemoContext context = new MyFormDemoContext())
{
valpara.CreatedBy = 1;
valpara.CreatedDate = DateTime.Now;
valpara.IsActive = true;
valpara.ModifyBy = 1;
valpara.ModifyDate = DateTime.Now;
valpara.IsDeleted = false;
valpara.ModifyDate = DateTime.Now;
context.Entry(valpara).State = System.Data.EntityState.Modified;
context.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
} }
1.currently when i create the module(entry) createdDate goes as current date
2. When i edit the module, modifiedDate and createdDate goes same
My expections
I want the createdDate Remains same when i Modify or edit the entry only modified date will be updated
When i edit the module, modifiedDate and createdDate goes same
Well, that's because in your Edit action you are specifically setting the CreatedDate, remove this line
valpara.CreatedDate = DateTime.Now
and only the ModifiedDate will be updated. However, a better approach would be to have your DB configured to set the date automatically (e.g. if you are using MSSQL set the default value to GetUtcDate()) and have EF pull that value instead of setting it client-side.
You need to set DatabaseGeneratedOption.Identity on that particular field which tells EF that the DB will generate the value.
FYI - you should really consider storing your dates as UTC rather than local i.e. use DateTime.UtcNow rather than DateTime.Now.
As well as the above, in your Edit you are actually re-creating a new entry each time. If you want to modify an existing record then you need to pull that record out of the DB first e.g.
using (MyFormDemoContext context = new MyFormDemoContext())
{
var record = context.MasterForms.SingleOrDefault(x => x.ID == id);
if (record != null)
{
record.ModifyBy = 1;
record.ModifyDate = DateTime.UtcNow;
context.SaveChanges();
}
}
Related
I'm using EF6 with ASP.Net. I'm trying to add items to the Jobs list in the following model:
EDIT:
My goal is to save the changes I make to the Timecards.Jobs list through a PUT method in such a way that I can retrieve them through a GET method.
public class Timecard
{
[Key]
public long TimecardID { get; set; }
[Required]
public DateTime StartDate { get; set; }
[Required]
public DateTime EndDate { get; set; }
[Required]
public long EmployeesID { get; set; }
[Required]
public decimal Hours { get; set; }
[Required]
public ICollection<int> Jobs { get; set; } = new List<int>();
public List<DateTime> Days { get; set; } = new List<DateTime>();
}
And I believe i'm doing so, i'm checking the states change in my PUT method:
// PUT: api/TimecardsAPI/5
[ResponseType(typeof(void))]
public IHttpActionResult PutTimecard(int id, Job job)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
try
{
Timecard card = db.Timecards.Where(x => x.TimecardID == id).First();
var state = db.Entry(card).State;
db.Timecards.Attach(card);
state = db.Entry(card).State;
card.Jobs.Add((int)job.JobID);
db.Entry(card).State = EntityState.Modified;
state = db.Entry(card).State;
var result = db.SaveChanges();
state = db.Entry(card).State;
var change = db.Timecards.Where(x => x.TimecardID == id).First().Jobs;
}
catch (DbUpdateConcurrencyException)
{
if (!TimecardExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
Before returning from the put method, i have a var change to check the results of the Jobs list once i'm done working on it. Before I leave the put method, the changes to the Jobs list are accurate. However, when I do a get, I get all the correct data EXCEPT the list. It comes back as a 0 length list. Here's my get method, which also has the jobs list in a variable. This is where the list comes back as size 0:
// GET: api/TimecardsAPI
public IQueryable<Timecard> GetTimecards()
{
var change = db.Timecards.Where(x => x.TimecardID == 6).First().Jobs;
//In this example, six is the id of the timecard in question. Only hardcoded here
//for debugging.
return db.Timecards;
}
and my dbcontext:
public class ClockedWebContext : DbContext
{
public ClockedWebContext() : base("name=ClockedWebContext")
{
}
public DbSet<Job> Jobs { get; set; }
public System.Data.Entity.DbSet<ClockedWeb.Models.PayPeriod> PayPeriods { get; set; }
public System.Data.Entity.DbSet<ClockedWeb.Models.Employee> Employees { get; set; }
public System.Data.Entity.DbSet<ClockedWeb.Models.Timecard> Timecards { get; set; }
}
There are many similar questions on SO but I have not found information yet that has helped me solve my issue. I have no idea what I'm doing wrong, but I've lost days on this and I could really use some help. thank you.
Generally storing multiples values in column is an indication of poor database design. Relational databases are designed specifically to store one value per row/column combination. In order to store more than one value, you must serialize your list into a single value for storage, then deserialize it upon retrieval or you can use many-to-one relationship then you should use an extra table with a foreign key constraint. There is no other way to do so in RDMS.
If you use serialize approach, then your model look like--
public class Timecard
{
[Key]
public long TimecardID { get; set; }
[Required]
public DateTime StartDate { get; set; }
[Required]
public DateTime EndDate { get; set; }
[Required]
public long EmployeesID { get; set; }
[Required]
public decimal Hours { get; set; }
[NotMapped]
public List<int> JobList { get; set; } = new List<int>();
[Required]
public string Jobs
{
get => string.Join(",", JobList);
set
{
if (string.IsNullOrEmpty(value)) JobList = new List<int>();
else
{
JobList = !string.IsNullOrWhiteSpace(value) && value.Contains(",")
? value.Split(',').Select(s => Convert.ToInt32(s.Trim())).ToList()
: !string.IsNullOrWhiteSpace(value) && !value.Contains(",")
? new List<int>()
: new List<int>();
}
}
}
//have to change also
public List<DateTime> Days { get; set; } = new List<DateTime>();//Follow previous technique
}
Then you can do your operation as you doing. just it's insert data as a coma separated string.
I am not getting you correctly but if you not getting the update after you changed your entity then can you please add below line
db.savechanges();
Model
public partial class MemberModel
{
[Key]
public int MemberID { get; set; }
[Required]
[Unique_Member]
[StringLength(255)]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Unique_Member]
[StringLength(255)]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name="Name")]
public string FullName { get { return string.Format(FirstName + " " + LastName); } }
[Required]
[StringLength(355)]
public string Address { get; set; }
[Required(ErrorMessage="The City field is Required")]
public int CityID { get; set; }
[Required(ErrorMessage = "The Country field is Required")]
public int CountryID { get; set; }
[Required]
[RegularExpression(#"^((0092))-{0,1}\d{3}-{0,1}\d{7}$|^\d{4}$|^\d{4}-\d{7}$", ErrorMessage = "Invalid Phone number")]
[Unique_Member]
public string Pin { get; set; }
[Display(Name="Mobile No.")]
[Required(ErrorMessage="Mobile No. Required")]
[RegularExpression(#"^((\+92)|(0092))-{0,1}\d{3}-{0,1}\d{7}$|^\d{11}$|^\d{4}-\d{7}$",ErrorMessage="Invalid Phone number")]
public string Phone { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
public virtual List<Order_SummeryModel> Order_Summeries { get; set; }
public virtual CountryModel Country { get; set; }
public virtual CityModel City { get; set; }
}
Custom Validation [Unique_Member]
its a custom validation for three properties "Pin","FirstName" and "LastName" which i made for create new member. It checks whether fullname and pin of new member is unique or not.
its works perfectly for create action but in edit action this restrict me to update the member model, i want to disable it for edit action, or there is another way to update the model with disable it.
public class Unique_MemberAttribute : ValidationAttribute
{
private static int count;
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
Context_getway db = new Context_getway();
string membervalue = value.ToString();
//var count = db.Members.Where((x => x.Name == membervalue || x.Pin == membervalue || x.Email == membervalue)).Count();
var count_fname = db.Members.Where(x => x.FirstName == membervalue).Count();
var count_lname = db.Members.Where(x => x.LastName == membervalue).Count();
var count_pin = db.Members.Where(x => x.Pin == membervalue).Count();
if ((count_fname != 0)||(count_lname != 0))
{
count++;
if (count == 2)
{
return new ValidationResult("Member Already Exist with the same Full Name (Change First Name OR Last Name)!");
}
}
if (count_pin != 0)
{
return new ValidationResult("Member Already Exist with the same Pin!");
}
return ValidationResult.Success;
}
}
[MetadataType(typeof(MemberModel))]
public partial class MemberModel
{
}
Member Controller (edit action)
[HttpGet]
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
else
{
var member = db.Members.Find(id);
ViewBag.CountryID = new SelectList(db.CountryModels.ToList(), "CountryID", "Country",member.CountryID);
ViewBag.CityID = new SelectList(db.CityModels.ToList(), "CityID", "City",member.CityID);
if (member != null)
{
return View(member);
}
else
return HttpNotFound();
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(MemberModel member)
{
try
{
if (ModelState.IsValid)
{
db.Entry(member).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
TempData["Msg"] = "Update Successfully";
return RedirectToAction("Index");
}
else
{
ViewBag.CountryID = new SelectList(db.CountryModels.ToList(), "CountryID", "Country",member.CountryID);
ViewBag.CityID = new SelectList(db.CityModels.ToList(), "CityID", "City",,member.CityID);
return View(member);
}
}
catch(Exception e)
{
TempData["Msg"] = "Update Unsuccessfully: "+ e.Message;
return View();
}
}
Try this:
ModelState.Remove("PropertyNameInModel");
You should still do the validation on Edit action method. Otherwise user can edit a record and select a unique combination already used by another record. You should simply use the Id property in your where clause to check any record other than the currently editing record.
So the first step is to get the Id property value of the current entity/view model you are validating. Then use the value in your where clauses.
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
var idProperty = validationContext.ObjectType.GetProperty("MemberID");
var idValueObj = idProperty.GetValue(validationContext.ObjectInstance, null);
var id = 0;
if (idValueObj != null)
id = (int) idValueObj;
var db = new Context_getway();
string membervalue = value.ToString();
var count_fname = db.Members.Count(x => x.FirstName == membervalue && x.UserId!=id);
//Your existing code goes here. Make sure to use the id value in your WHERE clauses
}
I just hardcoded the property name ("MemberID") in the answer to give you the idea. But if you want more flexibility, you can pass that when you use the attribute as mentioned in this answer.
Also you should double check your conditions. I find issues with your code. What if the value of your count variable valus is more than 1(ex:2)), then your if (count == 2) will not return true (because your count is more than 2. I am not sure your business requirements/rules. But if you are looking for unique full names, you can create a single LINQ statement to do that ( Use Any method instead of getting Count as needed)
One way is to remove the error from ModelState in the Edit Controller action, right before checking if the model is valid.
But the better way is to separate your Edit and Insert models.
The Edit Model will have all validation rules for edit; and the Insert model will be inherited from the Edit model and overriding some properties with additional validation rules.
public partial class EditMemberModel
{
[Key]
public int MemberID { get; set; }
[Required]
[StringLength(255)] // Removed the Unique_Member rule**
[Display(Name = "First Name")]
public virtual string FirstName { get; set; }
/// etc.
}
public partial class InsertMemberModel : EditMemberModel
{
[Required]
[Unique_Member]
[StringLength(255)]
[Display(Name = "First Name")]
public override string FirstName { get; set; }
/// etc.
}
I started a default MVC project with Identity and EF.
In my app users will be able to create and edit some records.
In the table for these records, I want to have the ids of users who created the record and who updated lastly.
My model class is like:
public class Record
{
public int ID { get; set; }
public DateTime CreateTime { get; set; }
public string CreatingUserID { get; set; }
public string UpdatingUserID { get; set; }
public DateTime UpdateTime { get; set; }
public Enums.RecordStatus Status { get; set; }
}
And in RecordsController, I save new records to db like this:
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(FormCollection form, RecordCreateVM vm)
{
string userId = User.Identity.GetUserId();
DateTime now = DateTime.Now;
Record rec = new Record ();
if (ModelState.IsValid)
{
int newRecordId;
using (RecordRepository wr = new RecordRepository())
{
UpdateModel(rec);
rec.CreateTime = now;
rec.UpdateTime = now;
rec.CreatingUserID = userId;
rec.UpdatingUserID = userId;
rec.Status = Enums.RecordStatus.Active;
Record result = wr.Add(rec);
wr.SaveChanges();
newRecordId = result.ID;
}
}
}
When I am listing these records, I also want my page to display these users' usernames.
I get all the active records from the repository I created.
public ActionResult Index()
{
RecordListVMviewModel = new RecordListVM();
using (RecordRepository wr = new (RecordRepository())
{
viewModel.Records = wr.GetAll();
}
return View(viewModel);
}
And this is the repository code:
public class RecordRepository: Repository<Record>
{
public override List<Record> GetAll()
{
IQueryable<Record> activeRecords = DbSet.Where(w => w.Status == Enums.RecordStatus.Active);
return activeRecords.ToList();
}
}
Where do I have to make changes? Can you give me an sample code for usages like this?
Thank you.
You need to change
public string CreatingUserID { get; set; }
public string UpdatingUserID { get; set; }
to something like:
public User CreatingUser { get; set; }
public User UpdatingUser { get; set; }
Set the ID's during the creation of new RecordRepository()
Then access them as Record.CreatingUser.FirstName ect
I have an Asp.Net MVC5 project which I need some help with. The Logic is that a Customer needs to have an agreement. This is fine because I can create the first agreement. The problem I am having is that if another agreement needs to be created for the customer it can't be within the same period as the existing one. Initially I am thinking of placing something into the Agreement controller in the Create method to do the check.
What I have currently is
Controller:
// GET: Agreements/Create
public ActionResult Create(int? Id, string Name)
{
if (Id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Agreement model = new Agreement();
// model.FullName = Name;
model.CustomerId = Id;
ViewBag.CustomerId = new SelectList(db.Customers, "CustomerId", "Name");
ViewBag.SupplierId = new SelectList(db.Suppliers, "SupplierId", "Name");
return View(model);
}
// POST: Agreements/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "AgreementId,CustomerId,CustomerHasAgreement,SupplierId,Start,End,AgreementPlanId,AgreementType")] Agreement agreement)
{
if (ModelState.IsValid)
{
var bExist = db.Agreements.Any(s => (s.Start <= agreement.End && s.End >= agreement.Start)); //or your check logic
if (!bExist)
{
db.Agreements.Add(agreement);
db.SaveChanges();
return RedirectToAction("Details", "Agreements", new { id = agreement.AgreementId });
}
else
ModelState.AddModelError("Error", "Sorry something happened unexpectedly !!!");
return RedirectToAction("Index");
}
ViewBag.CustomerId = new SelectList(db.Customers, "CustomerId", "Name", agreement.CustomerId);
ViewBag.SupplierId = new SelectList(db.Suppliers, "SupplierId", "Name", agreement.SupplierId);
return View(agreement);
}
Model:
public class Agreement
{
public int AgreementId { get; set; }
public int? CustomerId { get; set; }
[HiddenInput(DisplayValue = false)]
public bool CustomerHasAgreement { get; set; }
public int SupplierId { get; set; }
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime? Start { get; set; }
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime? End { get; set; }
public int? AgreementPlanId { get; set; }
public virtual Customer Customer { get; set; }
public virtual Supplier Supplier { get; set; }
public virtual Plan Plans { get; set; }
public int weeks { get; set; }
public AgreementType AgreementType { get; set; }
public string FullName { get; set; }
}
public enum AgreementType
{
Low = 1,
Moderate = 2,
High = 3,
Emergency = 4,
Temporary = 5,
[Display(Name = "Long Term")]
Long_Term = 6
}
}
I have tried to use a LINQ statement to check to see if the new agreement is greater than the end date of the old agreement.
var bExist = db.Agreements.Any(s => (s.Start <= agreement.End && s.End >= agreement.Start)); //or your check logic
This only seems to either skip over the if statement and not insert the record
Please can someone help me please. I have tried going through the Microsoft tutorial http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/advanced-entity-framework-scenarios-for-an-mvc-web-application
but seem to constantly get stuck when trying to implement it into my solution.
Many thanks
Mark
#markabarmi Do an OR operator. You're looking for 1 or 2 of 2 possible issues. Doesn't need to have both to trigger bExists to be true. Also limit that result set to your specific customer in question.
var bExist = db.Agreements.Any(s => (s.CustomerId == agreement.CustomerId) && ((s.Start <= agreement.End) || (s.End >= agreement.Start)));
I have class User in my project and have model UserRow (for showing user in view)
it's UserRow
using System;
namespace Argussite.SupplierServices.ViewModels
{
public class UserRow
{
public Guid Id { get; set; }
public string FullName { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Status { get; set; }
public int Role { get; set; }
public Guid SupplierId { get; set; }
public bool ActionsAllowed { get; set; }
public bool MailResendRequired { get; set; }
}
}
and I need to add in my controller checking if ActionsAllowed
[HttpPost]
public ActionResult Unlock(Guid id)
{
var user = Context.Users.Find(id);
if (user == null)
{
return Json(CommandResult.Failure("User was not found. Please, refresh the grid and try again."));
}
var checkActionsAllowed = Context.Users.AsNoTracking()
.Select(e => new UserRow
{
Id = e.Id,
ActionsAllowed = e.ActionsAllowed
};
if (checkActionsAllowed == true)
{
user.Status = UserStatus.Active;
return Json(CommandResult.Success(string.Format("User {0} has been unlocked.", user.FullName)));
}
else return;
}
but I got error with ActionsAllowed = e.ActionsAllowed and
in else return;
Help me please to solve this problem.
You have two problems:
Context.Users.AsNoTracking()
.Select(e => new UserRow
{
ActionsAllowed = e.ActionsAllowed
};
returns a list of objects, not a single object.
You have queried the user above, so i guess you can write simply:
if (user.ActionsAllowed) {
user.Status = UserStatus.Active;
return Json(CommandResult.Success...);
}
The second problem is the return; statement.
Your method returns an action result, so you have to return something.
For example
return Json(CommandResult.Failure(
"ActionsAllowed = false"));
First error sounds like you User class doesn't provide a ActionsAllowed Boolean property, while the second error happens because you need to return something from the method that can be interpreted as an ActionResult.
EDIT:
Hmm, I didn't notice this the first time, but this:
var checkActionsAllowed = Context.Users.AsNoTracking()
.Select(e => new UserRow
{
Id = e.Id,
ActionsAllowed = e.ActionsAllowed
};
followed by this:
if (checkActionsAllowed == true)
makes no sense - you're not returning a boolean result from a Select method, but rather an IEnumerable. Perhaps you should add your User schema to your question so that it's more obvious what you're trying to accomplish.