Skip to main content

Overview

The Product model represents items in the supermarket inventory. It includes pricing information, stock levels, and a relationship to the Category model for product classification.

Class Definition

using System.ComponentModel.DataAnnotations.Schema;

namespace SupermarketWEB.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }

        [Column(TypeName = "decimal(6,2)")]
        public decimal Price { get; set; }
        public int Stock { get; set; }
        public int CategoryId { get; set; }
        public Category? Category { get; set; }
    }
}

Properties

Id
int
required
Primary key and unique identifier for the product. Auto-generated by the database.
Name
string
required
The product name or title displayed to customers and used in inventory management.
Price
decimal
required
Product price with precision of 6 digits total and 2 decimal places. Stored as decimal(6,2) in the database, allowing values up to 9999.99.Column Attribute: [Column(TypeName = "decimal(6,2)")] ensures precise decimal storage without floating-point errors.
Stock
int
required
Current inventory quantity available for sale. Used for stock management and availability checks.
CategoryId
int
required
Foreign key reference to the Category table. Establishes the many-to-one relationship between products and categories.
Category
Category
Navigation property to the related Category entity. Nullable to support lazy loading and optional eager loading scenarios.

Data Annotations

Column Type Specification

The Price property uses a column type annotation to ensure precise decimal handling:
[Column(TypeName = "decimal(6,2)")]
public decimal Price { get; set; }
The decimal(6,2) type specification means:
  • 6: Total number of digits (precision)
  • 2: Number of digits after decimal point (scale)
  • Range: -9999.99 to 9999.99
This prevents floating-point arithmetic errors common with float or double types, which is critical for financial calculations.

Relationships

Category Relationship (Many-to-One)

Each product belongs to exactly one category:
public int CategoryId { get; set; }      // Foreign key
public Category? Category { get; set; }  // Navigation property
Loading Related Data:
// Load products with their categories
var products = await context.Products
    .Include(p => p.Category)
    .ToListAsync();

foreach (var product in products)
{
    Console.WriteLine($"{product.Name} - {product.Category.Name}");
}

Usage Examples

Creating a New Product

var product = new Product
{
    Name = "Organic Apples",
    Price = 3.99m,
    Stock = 150,
    CategoryId = 1  // Reference to Fruits category
};

context.Products.Add(product);
await context.SaveChangesAsync();

Updating Stock

var product = await context.Products.FindAsync(productId);
if (product != null)
{
    product.Stock -= quantitySold;
    await context.SaveChangesAsync();
}

Querying Products by Category

var categoryProducts = await context.Products
    .Where(p => p.CategoryId == categoryId)
    .OrderBy(p => p.Name)
    .ToListAsync();

Low Stock Alert

var lowStockProducts = await context.Products
    .Include(p => p.Category)
    .Where(p => p.Stock < 10)
    .Select(p => new {
        p.Name,
        p.Stock,
        Category = p.Category.Name
    })
    .ToListAsync();

Database Schema

When migrated to the database, the Product table has the following structure:
ColumnTypeNullableKey
IdintNoPrimary Key (Identity)
Namenvarchar(MAX)No
Pricedecimal(6,2)No
StockintNo
CategoryIdintNoForeign Key → Categories.Id
The Category navigation property does not create a database column. It’s used by Entity Framework for relationship mapping.

Best Practices

  1. Price Precision: Always use decimal type for currency to avoid rounding errors
  2. Stock Validation: Implement business logic to prevent negative stock values
  3. Category Assignment: Ensure CategoryId references a valid Category before saving
  4. Eager Loading: Use .Include() when you know you’ll need the Category to avoid N+1 queries
  5. Null Checks: Always check if Category is null before accessing its properties if not using eager loading

Build docs developers (and LLMs) love