Skip to main content

Entities & Data Models

Level: Beginner

ℹ️ Where This Fits

Entity models are C# classes that map to database tables. Configuring them with data annotations or Fluent API defines the database schema automatically.

ℹ️ What You'll Learn
  • Entity class: C# class representing database table (Student class = Students table)
  • Property mapping: Class properties become table columns
  • Key attribute: [Key] marks primary key property
  • Required attribute: [Required] makes column NOT NULL
  • MaxLength: [MaxLength(100)] limits string column length
  • Column attribute: [Column("StudentName")] maps property to different column name
  • Table attribute: [Table("tbl_Students")] maps class to different table name
  • Default values: [DefaultValue(true)] or HasDefaultValue() in Fluent API
  • Data types: Property type maps to SQL type (string→NVARCHAR, int→INT, DateTime→DATETIME)
  • Computed columns: [Computed] for SQL-calculated columns
  • Navigation properties: public List<Exam> Exams { get; set; } for relationships
  • Foreign key: [ForeignKey("StudentId")] marks foreign key property
  • School Management entities: Student, Teacher, Exam, ExamResult, Fee, FeePayment, Attendance
  • Fluent API: Alternative to data annotations (modelBuilder.Entity<Student>()...)
  • Common mistakes: Forgetting primary key, using nullable reference types incorrectly, circular references

Basic Student Entity

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
[Key]
public int Id { get; set; }

[Required]
[MaxLength(100)]
public string Name { get; set; } = string.Empty;

[Required]
[MaxLength(10)]
public string ClassName { get; set; } = string.Empty;

[Required]
[MaxLength(20)]
public string RollNumber { get; set; } = string.Empty;

public DateTime DateOfBirth { get; set; }

[Required]
public StudentStatus Status { get; set; } = StudentStatus.Active;

public DateTime CreatedAt { get; set; } = DateTime.UtcNow;

// Navigation properties
public List<Exam> Exams { get; set; } = new();
public List<FeeAccount> FeeAccounts { get; set; } = new();
public List<Attendance> Attendance { get; set; } = new();
}

public enum StudentStatus { Active, Inactive, Graduated, Transferred }

Exam Entity with Foreign Key

public class Exam
{
[Key]
public int Id { get; set; }

[Required]
[MaxLength(100)]
public string ExamName { get; set; } = string.Empty;

[Required]
public ExamType Type { get; set; }

public DateTime ExamDate { get; set; }

public int MaxMarks { get; set; }

// Foreign key to Subject
[ForeignKey("Subject")]
public int SubjectId { get; set; }
public Subject Subject { get; set; }

// Navigation properties
public List<ExamResult> Results { get; set; } = new();
}

public enum ExamType { UnitTest, MidTerm, Final, Practical }

Many-to-Many Example - Student and Subject

public class Student
{
public int Id { get; set; }
public string Name { get; set; }

// Many-to-many with Subject through StudentSubject junction table
public List<StudentSubject> StudentSubjects { get; set; } = new();
}

public class Subject
{
public int Id { get; set; }
public string Name { get; set; }

public List<StudentSubject> StudentSubjects { get; set; } = new();
}

public class StudentSubject
{
public int StudentId { get; set; }
public Student Student { get; set; }

public int SubjectId { get; set; }
public Subject Subject { get; set; }

// Composite primary key
}

Fluent API Configuration

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Student configuration
modelBuilder.Entity<Student>(entity =>
{
entity.HasKey(e => e.Id);

entity.Property(e => e.Name)
.IsRequired()
.HasMaxLength(100);

entity.Property(e => e.ClassName)
.IsRequired()
.HasMaxLength(10);

entity.HasMany(e => e.Exams)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
});

// Exam configuration
modelBuilder.Entity<Exam>(entity =>
{
entity.HasKey(e => e.Id);
entity.HasOne(e => e.Subject).WithMany();
});

// StudentSubject (many-to-many)
modelBuilder.Entity<StudentSubject>(entity =>
{
entity.HasKey(e => new { e.StudentId, e.SubjectId });

entity.HasOne(e => e.Student)
.WithMany(s => s.StudentSubjects)
.HasForeignKey(e => e.StudentId);

entity.HasOne(e => e.Subject)
.WithMany(s => s.StudentSubjects)
.HasForeignKey(e => e.SubjectId);
});
}

Best Practices

✓ Always define primary keys ✓ Use [Required] for NOT NULL columns ✓ Use [MaxLength] for string limits ✓ Initialize collections in property initializer ✓ Use = string.Empty for required strings

💡 Nullable Reference Types

Enable nullable reference types in .csproj:

<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>

Then use string? for optional, string for required.

🤖Use AI to Learn Faster

Use ChatGPT, Claude, or Copilot to go deeper on Entities & Data Models. Try these prompts:

  • "What's the difference between data annotations and Fluent API?"
  • "How do you define a many-to-many relationship?"
  • "What does the [Key] attribute do?"
  • "How do you set a default value for a column?"

💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.

Next Article

-> 04. Migrations

nexcoding.in