I have a viewModel that contains the following:
public class CreateCardViewModel
{
[HiddenInput(DisplayValue = false)]
public int SetId { get; set; }
[Required]
public IList<Side> Sides { get; set; }
[Required]
public int Stage { get; set; }
[Required]
[DataType(DataType.Date)]
[HiddenInput(DisplayValue = false)]
public DateTime DateCreated { get; set; }
[Required]
public bool IsReady { get; set; }
}
The model is as follows:
public class Card
{
public virtual int CardId { get; set; }
// belongs to a Set
public virtual int SetId { get; set; }
public virtual Set Set { get; set; }
// has Sides
public virtual IList<Side> Sides { get; set; }
// is in a certain Stage
public virtual int Stage { get; set; }
// is ready to study
public virtual bool IsReady { get; set; }
public virtual DateTime DateCreated { get; set; }
}
How can I set a default value for DateCreated?
Would the method change if I want to insert a blank Side into Sides upon Card creation?
You could set defaults in the constructor:
public CreateCardViewModel()
{
DateCreated = DateTime.Now;
Sides = new List<Side> { new Side() };
}
Caveat: There is an issue with using DateTime.Now from a unit testing perspective. If you're unit testing your ViewModel creation and need to be able to verify that the created date is set to a known value, you can look at creating a separate concept for time, as detailed in Ayende's blog. You basically create a static func, SystemTime, that you can set to a known value in your tests. If you don't set it, it defaults to DateTime.Now:
public static class SystemTime
{
public static Func<DateTime> Now = () => DateTime.Now;
}
Your constructor code then becomes:
public CreateCardViewModel()
{
DateCreated = SystemTime.Now();
Sides = new List<Side> { new Side() };
}
If you need to actually set the time to a known value, you do this:
SystemTime.Now = () => new DateTime(2013, 2, 11, 17, 41, 12);
I agree on The SystemTime approach.
Although, I personally don't like setting the CreatedDate on the constructor, since there can be a short time lapse since you instantiate the object and when you persist it to the database. (And here I am assuming you definitely are)
You could make all your domain objects inherit from an interface like this one:
public interface ITimeStamped
{
DateTime DateCreated { get; set; }
}
And then on the Commit method int the Context class I would do something like this to set the date for all entities that implement the interface:
foreach (var entry in ChangeTracker.Entries<ITimeStamped>()
.Where(entry => entry.State == EntityState.Added))
{
entry.Entity.DateCreated = SystemTime.Now();
}
This way you're totally certain that the entity is stored with the correct DateTime when it was persisted on the database.
Related
I have this code:
Mapper.AddMap<Product, DetailsVM>(src =>
{
var res = new DetailsVM();
res.InjectFrom(src); // maps properties with same name and type
res.test = "asd";
return res;
});
productVM.InjectFrom(test);
I have everything working and this is my VM:
public int ProductId { get; set; }
public decimal Cost { get; set; }
public decimal UnitPrice { get; set; }
public int OnHandQty { get; set; }
public ProductPicture thumb { get; set; }
public ProductPicture main { get; set; }
public string test { get; set; }
the actual model doesn't have the property test, I simply want to set test to any string. how do I do it? I keep on getting null whenever i try to map.
you need to call Mapper.Map instead of InjectFrom,
InjectFrom is not affected by Mapper.AddMap
I have simple Model defined as
public class Project
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int StatusId { get; set; }
public virtual Status Status { get; set; }
}
public class Status
{
public int Id { get; set; }
public string Name { get; set; }
}
So, currently If I try to create a new Project Entity with breeze, it initializes the navigation property "Status" with null. How can I initialize it with default value? Note that, I don't want any binding with drop down field for this field at least for create operation.
function createNewProject() {
return manager.createEntity('Project');
}
You can define a custom constructor for the Project entity type and set a default StatusId value in there. The Status navigation property will be set to the relevant status entity (assuming the entity is in the breeze cache). For example:
function Project() {
this.StatusId = desiredDefaultStatusEntityId;
}
var manager = new breeze.EntityManager('...');
manager.metadataStore.registerEntityTypeCtor('Project', Project);
Take a look at Extending entities for some more information on extending entities.
I use Asp.Net MVC, Entity Framework. I have a form it looks like below.
Here, dropdownlist is filled from a table(types). Checkboxes is filled from another table(test). Tables are like below:
public class Types
{
public int TypesID{get;set;}
public string TestName { get; set; }
public string TestExplanation { get; set; }
public int TestTime { get; set; }
}
public class Tests
{
public int TestID{get;set;
public string Name { get; set; }
public string Code { get; set; }
}
public class Types_Tests
{
public int Types_TestsID{ get; set; }
public int TypesID { get; set; }
public int TestsID { get; set; }
public virtual Types Types { get; set; }
public virtual Tests Tests { get; set; }
}
Types_test table is relation table between Types and Tests. When I click Kaydet button, it shuld save type and checked tests. I made this operation using ViewBag, javascript and hdnvalue.I added checked checkboz values to a hdntext. I made saving process like below:
[HttpPost]
public ActionResult Index(string drpType, string hdntesttypes)
{
var TypeList = Types.GetAll();
ViewBag.TypesList = new SelectList(TypeList, "Id", "Name");
var testypeList = testTypes.GetAll();
ViewBag.TestTypesList = new SelectList(testypeList, "Id", "TestName");
GenericRepository<TestDisabledTypes> testDisabledRepository = new GenericRepository<TestDisabledTypes>(_context);
if (!string.IsNullOrEmpty(hdntesttypes))
{
string[] disabletypesArray = hdntesttypes.Split(',');
using (TransactionScope trns = new TransactionScope())
{
for (int i = 0; i < disabletypesArray.Length; i++)
{
Test_Types types = new Test_Types ();
types.TestTypesID = Convert.ToInt32(disabletypesArray[i]);
types.TypesID = Convert.ToInt32(drpType);
testDisabledRepository.Insert(types);
}
trns.Complete();
}
}
return View();
}
It wokrs. But I search better solution for this process. Can someone give me any idea?
Thanks.
If you don't need additional attributes for your entity class, you don't need create link table.
Just define the following class, and EF will generate the link table for you automatically.
public class Type
{
public int TypesID{get;set;}
public string TestName { get; set; }
public string TestExplanation { get; set; }
public int TestTime { get; set; }
public ICollection<Test> Tests { get; set; }
}
public class Test
{
public int TestID{get;set;
public string Name { get; set; }
public string Code { get; set; }
public ICollection<Type> Types {get;set;}
}
Well, in EntityFramework if you want to create a many to many relation object you need to create new object of "linking" entity. Unfortunately, it is not possible to add first object, add second object and say "Guys, you are in many to many relationships. Are you happy then?" :) You need to create relation object, set appropriate fields in it (I think these are ids of two objects itself) and add it to relation collection (entity) in your model. But before doing so you need to be sure that objects with data you are linking with are already exists in database. Otherwise you'll get an error
Also it's not necessary to create manually transaction because EF does it for you automatically each time you get/save your data
I have the following class that's used by my MVC3 application. I would like
to simplify the updating of the class so that when a new class object is
created then the Created and CreatedBy fields get set automatically.
I'd also like to make it so that the Modified and ModifiedBy fields get
updated automatically.
Is there a way that I could do this?
The class is used in MVCnamespace Storage.Models
{
public class Topic : TableServiceEntity
{
[DisplayName("Partition Key")]
public override string PartitionKey { get; set; }
[DisplayName("Row Key")]
public override string RowKey { get; set; }
[DisplayName("Description")]
public string Description { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
public String CreatedBy { get; set; }
public string ModifiedBy { get; set; }
}
}
Set the defaults in the constructor for the class
public class Topic
{
public Topic()
{
this.Created = DateTime.Now;
this.CreatedBy = UserName;
}
[DisplayName("Partition Key")]
public override string PartitionKey { get; set; }
[DisplayName("Row Key")]
public override string RowKey { get; set; }
[DisplayName("Description")]
public string Description { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
public String CreatedBy { get; set; }
public string ModifiedBy { get; set; }
}
jonathan,
Jason's answer above with the logic contained within the constructors is a perfectly valid and clean way of doing this and I wouldn't argue with that (and have done it myself for more 'static' properties). However, given that there could be a timelapse between the creation of the object and the actual save, then you may also want to consider putting this logic into your controller (or service layer).
this would look roughly like this:
public ActionResult Create(MyCreateViewModel viewModel)
{
if (ModelState.IsValid)
{
viewModel.Entity.Created = DateTime.UtcNow;
_myService.Insert(viewModel.Entity);
_myService.SaveChanges();
return this.RedirectToAction(x => x.Index());
} else {
PopulateViewModel(viewModel);
return View(viewModel);
}
}
likewise, you may have a LastEdit datetime that you want to track. use the Edit action similarly:
public ActionResult Edit(MyEditViewModel viewModel)
{
if (ModelState.IsValid)
{
viewModel.Entity.LastEditDate= DateTime.UtcNow;
_myService.AttachAndUpdate(viewModel.Entity);
_myService.SaveChanges();
return this.RedirectToAction(x => x.Index());
} else {
PopulateViewModel(viewModel);
return View(viewModel);
}
}
just another approach to ensure that datetime related properties are truly reflected.
In this solution i think you may have to make big change in your Repository/Service layer
define an Interface like :
public interface IHistoryLog
{
DateTime Created { get; set; }
DateTime Modified { get; set; }
string CreatedBy { get; set; }
string ModifiedBy { get; set; }
}
then:
public class Topic:IHistoryLog
{
// Implement interface..
}
then create a generic service class:
public abstract class CRUDService<TModel>
{
protected CRUDService(DataContext dataContext)
{
// data context to do generic CRUD stuff
}
public virtual Save(TModel model)
{
if(model is IHistoryLog)
{
// assign Createdby and Created
}
}
public virtual Update(TModel model)
{
if(model is IHistoryLog)
{
// assign ModifiedBy and Modified
}
}
}
How can I apply Required Attribute like validation to the following without knowing how many elements will be in each collection:
public class MyViewPageViewModel
{
[Required]
public List<int> IntCollection { get; set; }
[Required]
public Dictionary<int, string> IntAndStringAllValueCollection { get; set; }
[Required("Value")]
public Dictionary<int, string> IntAndStringValueValidationCollection { get; set; }
[Required("Name","HairColor")]
public List<Person> PersonNameValidationCollection { get; set; }
}
For IntCollection I want every element to be required. For IntAndStringAllValueCollection I want every Key and every Value to be required. For IntAndStringValueValidationCollection I do not want the Key to be required but I want the Value to be required.
Although I'd like to be able to do it as expressed above, one way to get around the problem is like so:
public class PageViewModel
{
public List<RequiredStartAndEndDateTuple> OnlineDates { get; set; }
}
public class RequiredStartAndEndDateTuple
{
public RequiredStartAndEndDateTuple() { }
public RequiredStartAndEndDateTuple(DateTime? startDate, DateTime? endDate)
{
OnlineStartDate = startDate;
OnlineEndDate = endDate;
}
[Required(ErrorMessage = "Start Date Required")]
public DateTime? OnlineStartDate { get; set; }
//-- Note, no attribute means end date not required
public DateTime? OnlineEndDate { get; set; }
}
And if you're interested in the Controller & View Bits, check out:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Specifically grab the project source code and check out the 'Sequential' page using the strongly typed helpers