views:

49

answers:

1

Hello!

I have been trying for quite a while to work out how to accomplish my mission, and in fact I am not even sure that the direction I am heading in, is indeed a diserable one in terms of my SQL tables - but it is the most concise I have been able to think up on.

My problem is fairly simple to describe. I have a table containing comments, with a foreign-key to my User table (which represents the author of the comment). In an attempt to properly support anonymous users I have decided to make this foreign key nullable - and I also provide 3 columns for specifying Name, Email and Website where I wish to store the information relevant in case the user is anonymous - these fields are also nullable.

So in short

  • If the user is logged in, the foreign-key will contain the ID of that user and Name, Email and Website will be null.
  • If the user is not logged in, the foreign-key will be null and Name, Email and Website will contain data about the user.

In my domain model I wish to map this to a User class (a property, Author, on my comment class). This User class then have a property called "IsAnonymous" - which should be set accordingly.

Ideally, I would have some mapping set up that would map this Author property depending on the values of the foreign-key and assign these properties correct. I already have a mapping for my User class that maps it to the User table, but I am not sure how I would do this the other way.

I have tried looking into the IUserType interface, but I can't quite understand how I would ago about this issue of having to read from 2 different tables.

Is there a reasonable way of doing this using my current database structure - or should I consider switching my layout, and if so, to what?

I switched from having a simple column in my User table indicating an anonymous user, but this started giving me issues when the Name column is set as a unique key. I want registered Users to have unique Name's but not anonymous Users.

Thanks for your time.

EDIT: Read over that and decided maybe some ASCII/pseudo-SQL diagrams would come in handy

User
-----
UserId Guid PRIMARY KEY
Name nvarchar(200) UNIQUE KEY NOT NULL
Email nvarchar(200) NOT NULL
Website nvarchar(200) NOT NULL

Comment
-------
CommentId Guid PRIMARY KEY
UserId GUID - FK-USER
Name nvarchar(200)
Email nvarchar(200)
Website nvarchar(200)
+1  A: 

I'd have something like that

//map this in NH
public virtual User LoggedInCreator {get;set;}
//Not mapped
public virtual User CreatorInformation {
    get {
        if(LoggedInCreator != null) return LoggedInCreator;
        return new User {
                Name = AnonymousCommenterName,
                Email = AnonymousCommenterEmail,
                Website= AnonymousCommenterWebsite
            };
    }
}
public void SetAnonymouscommenter(string name, string email, string website)
{
    LoggedInCreator = null;
    AnonymousCommenterName = name;
    AnonymousCommenterEmail = email;
    AnonymousCommenterWebsite = website;
}

However, if you want to do it in a much cleaner way, you'd use a great feature of NHibernate, which is being able to map Fields and also mapping properties that store their values in fields.
Here is what a cleaner implementation would be:

protected User _commenter;
public virtual User Commenter
{
    get {
        if(_commenter != null) return _commenter;
        return new User {
                Name = AnonymousCommenterName,
                Email = AnonymousCommenterEmail,
                Website= AnonymousCommenterWebsite
        };
    }
    set {
        bool isAnonymous = value.Id == 0;
        _commenter = isAnonymous ? null : value;
        AnonymousCommenterName = isAnonymous ? value.Name : null;
        AnonymousCommenterEmail = isAnonymous ? value.Email : null;
        AnonymousCommenterWebsite = isAnonymous ? value.Website : null;
    }
}

You can see they are essentially the same idea though, just some cleanup using NHibernate features.

Mohamed Meligy
This could work! I am currently working on an approach where i subclass my comment class into my NHibernate specific use case and use this only in my NHibernate code. I will return back once I am done testing this to see if it can work :).
kastermester
Thank you, your suggestions got me going in a way that seems to work. It's a bit of code to implement this in the NH layer, but on the other hand it makes this nice to work with elsewhere and it is stored in the database in a way that makes sense in my head :)
kastermester