Models & ViewModels in ASP.NET Core
Entity = DB shape. ViewModel = UI shape. Never send Entities to Views.
60-Second Version: Entity = what DB stores. ViewModel = what user sees. Controller maps Entity โ ViewModel. View never touches Entity.
1. Entity: Database Blueprint
Used by EF Core. Has every column, even secrets.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal CostPrice { get; set; } // Secret!
public decimal SellPrice { get; set; }
public DateTime CreatedAt { get; set; }
public virtual ICollection<OrderItem> OrderItems { get; set; } // Navigation
}
Problem: Send this to View โ HTML shows CostPrice. Or triggers lazy-loading = 50 DB queries.
2. ViewModel: Safe Shape for UI
Only what View needs. No secrets, no navigation props.
public class ProductListViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public decimal SellPrice { get; set; }
public string FormattedPrice => $"${SellPrice:F2}";
}
Rule: 1 View = 1 ViewModel. Don't reuse.
3. Mapping: Controller's Job
public async Task<IActionResult> Index()
{
var entities = await _db.Products.ToListAsync(); // Entity from DB
var vms = entities.Select(p => new ProductListViewModel
{
Id = p.Id,
Name = p.Name,
SellPrice = p.SellPrice
}).ToList(); // Map to ViewModel
return View(vms); // View gets safe data
}
4. Data Annotations: Validation Rules
Put rules on ViewModel, not Entity. EF ignores them.
public class ProductCreateViewModel
{
[Required(ErrorMessage = "Name is required")]
[StringLength(100)]
public string Name { get; set; }
[Range(0.01, 10000)]
public decimal SellPrice { get; set; }
}
Controller: if (!ModelState.IsValid) return View(vm); shows errors.
Beginner Trap: Rahul adds
[Required] to Entity. Migration adds NOT NULL to DB. Existing rows crash. Fix: Validation on ViewModel only. Entity = DB truth.
Quick Check ๐ง
Next: Model Binding & Validation - How data gets into actions and ModelState.
No comments yet. Be the first to share your thoughts!