0

I want to audit my Posts table by preserving whole record changes to a PostRevisions table before Post rows are updated. PostRevision entities should store all the Post entity columns along with a RevisionId column.

I want to map this with Fluent NHibernate. PostRevision entities should mirror the properties of Post entities, but without having to maintain two entity classes and mapping classes.

How should I design my entities and mappings to do achieve this?

Desired pseudocode for Post Edit

var post = _unitOfWork.CurrentSession.Get<Post>(id);
var postRevision = new PostRevision(post);

post.Content = "changed value"; // change some things here

_unitOfWork.CurrentSession.Save(post);
_unitOfWork.CurrentSession.Save(postRevision);

_unitOfWork.Commit();

PostRevision composition class:

public class PostRevision
{
    public virtual Guid Id { get; private set; }
    public virtual Post Post { get; set; }

    public PostRevision()
    {
    }

    public PostRevision(Post post)
    {
        this.Post = post;
    }
}

Possible Fluent Mapping:

public class PostRevisionMap : ClassMap<PostRevision>
{
    public PostRevisionMap()
    {
        Id(x => x.Id);
        Component(x => x.Post); // will something like this work?
    }
}
Petrus Theron
  • 27,855
  • 36
  • 153
  • 287

1 Answers1

0

the relation (I think) you're looking for is one-to-many: a Post has many PostRevisions.
a PostRevision references a single Post.
Therefore I think the correct mapping on the Post side would be

HasMany(x=> x.PostRevisions);  

and on the PostRevision side:

References(x=> x.Post).  

see the nHibernate docs for a more complete look on how to map these associations.

Edit
If you want to keep a history record for each revision of your post, you have 2 options:
1. add a boolean 'IsHistoric' field to your Post class. Whenever a Post is revised, you don't change the Post object itself, but rather mark it as 'IsHistoric = true' and create a new Post object which represents the revised Post. This is the method I use in my project.
2. Create a 'HistoricPost' class which inherits from Post. You don't have to repeat your mapping, and you can use a seperate table for this class (table-per-subclass strategy).
see here for further details.
I think you can also specify a different Id column for the child class, using Id(x => x.SomeOtherId); in the mapping of 'HistoricPost'. I haven't tried it though, so I'm not 100% sure.

J. Ed
  • 6,692
  • 4
  • 39
  • 55
  • @sJhonny, what should the class mapping for `PostRevisions` look like if I don't want to duplicate all the mapping properties? – Petrus Theron Apr 25 '11 at 07:50
  • The mapping would have exactly 2 lines- one to map the id (something like Id(x=> x.Id) ), and the other- the one i've posted. That's it. since the Post entity is already mapped on its own, you don't need to map it again. – J. Ed Apr 26 '11 at 06:24
  • @sJhonny, I'll make my question clearer. `Post` in `PostRevision` should be a value-object, not an entity reference. Before updating a Post record, its present value is preserved to the `PostRevisions` table. – Petrus Theron Apr 26 '11 at 08:49
  • sorry, I didn't realize that. in that case, I see 2 options- either create a new entity (PostHistory) which inherits from Post, and reference it in the PostRevision class (see this question- http://stackoverflow.com/questions/2041567/nhibernate-map-one-class-to-two-identical-tables). Another option is to add a boolean field to the Post class- IsHistoric (or some such). On every revision, you would actually create a new Post instance, and update the IsHistoric field of the existing one. – J. Ed Apr 26 '11 at 11:03
  • @sJhonny, for option 1, how can `PostHistory` inherit the mappings for `Post` without code-duplication? – Petrus Theron Apr 26 '11 at 11:21
  • Ah! I didn't know it could handle separate tables per subclass. Put that as your answer and I'll mark it as accepted. – Petrus Theron Apr 26 '11 at 15:46
  • @sJohnny, Can I unmap the parent class ID so the sub-class can have it's own ID? – Petrus Theron Apr 26 '11 at 15:50