Soft Deletes With NHibernate, Part II
After my previous post, Adam Bar suggested that setting an SQL Delete command might be a better idea, I actually agree with him, so I decided to post an alternative solution.
For those not familiar with the concept, NHibernate lets us specify SQL commands for all of the basic CRUD operations: loading, inserting, updating and deleting. The SQL can even be a stored procedure call. In this case, it’s the deleting that we’re after, and it is quite easy to configure:
1: public class RecordMapping : ClassMapping<Record>
2: {
3: public RecordMapping()
4: {
5: this.Table("record");
6: this.Lazy(true);
7: this.Where("deleted = 0");
8: this.SqlDelete("UPDATE record SET deleted = 0 WHERE record_id = ?");
9:
10: this.Id(x => x.RecordId, x =>
11: {
12: x.Column("record_id");
13: x.Generator(Generators.HighLow);
14: });
15:
16: this.Version(x => x.UpdatedAt, x =>
17: {
18: x.Column(y =>
19: {
20: y.NotNullable(true);
21: y.Name("updated_at");
22: });
23: x.Generated(VersionGeneration.Never);
24: x.Type(NHibernateUtil.UtcDateTime as IVersionType);
25: });
26:
27: this.Property(x => x.CreatedAt, x =>
28: {
29: x.Column("created_at");
30: x.NotNullable(true);
31: x.Update(false);
32: x.Insert(true);
33: });
34:
35: this.Property(x => x.CreatedBy, x =>
36: {
37: x.Column("created_by");
38: x.NotNullable(true);
39: x.Update(false);
40: x.Insert(true);
41: });
42:
43: this.Property(x => x.UpdatedBy, x =>
44: {
45: x.Column("updated_by");
46: x.NotNullable(true);
47: });
48:
49: this.Property(x => x.Name, x =>
50: {
51: x.Column("name");
52: x.Length(50);
53: x.NotNullable(true);
54: });
55:
56: this.Property(x => x.Deleted, x =>
57: {
58: x.Column("deleted");
59: x.NotNullable(true);
60: });
61:
62: this.ManyToOne(x => x.Parent, x =>
63: {
64: x.Column("parent_record_id");
65: x.NotNullable(false);
66: x.Lazy(LazyRelation.NoProxy);
67: x.Cascade(Cascade.All);
68: });
69:
70: this.Bag(x => x.Children, x =>
71: {
72: x.Inverse(true);
73: x.Cascade(Cascade.All | Cascade.DeleteOrphans);
74: x.SqlDelete("UPDATE record SET deleted = 1 WHERE record_id = ?");
75: x.Where("deleted = 0");
76: x.Key(y =>
77: {
78: y.Column("parent_record_id");
79: y.NotNullable(false);
80: });
81: }, x =>
82: {
83: x.OneToMany();
84: });
85: }
86: }
Notice the two calls to SqlDelete, one for the class itself, and the other for the Children collection. The former takes care of soft deleting the record itself, and the later, it’s children.
It is a more contained and straightforward solution, no need for registering listeners.