Entity Framework: Fluent API & Data Annotations Cheat Sheet
# 1. Primary Keys
Fluent API:
builder.HasKey(e => e.Id);
Data Annotations:
[Key]
public int Id { get; set; }
# 2. Composite Keys
Fluent API:
builder.HasKey(e => new { e.Key1, e.Key2 });
Data Annotations:
Not supported. Use Fluent API for composite keys.
# 3. Relationships
## One-to-One Relationship
Fluent API:
builder.HasOne(e => e.NavigationProperty)
.WithOne(e => e.InverseNavigationProperty)
.HasForeignKey<DependentEntity>(e => e.ForeignKeyProperty);
Data Annotations:
[ForeignKey("ForeignKeyProperty")]
public NavigationPropertyType NavigationProperty { get; set; }
## One-to-Many Relationship
Fluent API:
builder.HasOne(e => e.NavigationProperty)
.WithMany(e => e.CollectionNavigation)
.HasForeignKey(e => e.ForeignKeyProperty)
.OnDelete(DeleteBehavior.Cascade);
Data Annotations:
[ForeignKey("ForeignKeyProperty")]
public NavigationPropertyType NavigationProperty { get; set; }
## Many-to-Many Relationship
Fluent API:
builder.HasMany(e => e.NavigationCollection)
.WithMany(e => e.InverseCollection)
.UsingEntity<JoinEntity>(
j => j.ToTable("CustomTableName")
);
Data Annotations:
Not supported. Use Fluent API for many-to-many relationships.
# 4. Table Mapping
Fluent API:
builder.ToTable("CustomTableName");
Data Annotations:
[Table("CustomTableName")]
public class Entity { }
# 5. Column Mapping
Fluent API:
builder.Property(e => e.PropertyName)
.HasColumnName("CustomColumnName")
.HasColumnType("nvarchar(50)")
.IsRequired();
Data Annotations:
[Column("CustomColumnName", TypeName = "nvarchar(50)")]
[Required]
public string PropertyName { get; set; }
# 6. Default Values
Fluent API:
builder.Property(e => e.PropertyName)
.HasDefaultValue("DefaultValue");
Data Annotations:
Not supported. Use Fluent API for default values.
# 7. Indexes
Fluent API:
builder.HasIndex(e => e.PropertyName)
.IsUnique();
Data Annotations:
[Index(IsUnique = true)]
public string PropertyName { get; set; }
# 8. Ignore Properties
Fluent API:
builder.Ignore(e => e.PropertyName);
Data Annotations:
[NotMapped]
public string PropertyName { get; set; }
# 9. Required Properties
Fluent API:
builder.Property(e => e.PropertyName)
.IsRequired();
Data Annotations:
[Required]
public string PropertyName { get; set; }
# 10. String Length
Fluent API:
builder.Property(e => e.PropertyName)
.HasMaxLength(100);
Data Annotations:
[StringLength(100)]
public string PropertyName { get; set; }
# 11. Constraints
Fluent API:
Unique Constraints:
builder.HasIndex(e => e.PropertyName).IsUnique();
Check Constraints:
builder.HasCheckConstraint("CK_PropertyName", "PropertyName > 0");
Data Annotations:
Unique constraints and check constraints are not supported with data annotations.
# 12. Cascade Delete
Fluent API:
builder.HasOne(e => e.NavigationProperty)
.WithMany(e => e.CollectionNavigation)
.OnDelete(DeleteBehavior.Cascade);
Data Annotations:
Not configurable via annotations.
# 13. Enums
Fluent API:
builder.Property(e => e.EnumProperty)
.HasConversion<string>();
Data Annotations:
[Column(TypeName = "nvarchar(24)")]
public EnumType EnumProperty { get; set; }
# 14. Default Schema
Fluent API:
modelBuilder.HasDefaultSchema("CustomSchema");
Data Annotations:
Not supported. Use Fluent API for schema configuration.
# When to Use Fluent API vs. Data Annotations
- Fluent API: For advanced configurations, like composite keys, many-to-many relationships, default values, and
constraints.
- Data Annotations: For simple configurations directly on the entity properties.