Search code examples
asp.net-mvc-3castle-activerecord

Can't Persist Field to Aspnet_Users via NHibernate/ActiveRecord


I'm using ActiveRecord with NHibernate on the backend. I've set up a mapping for Users; I can create/retrieve/register users without any issues.

I now want to add an association called Role to my users (many users per role). I've created the appropriate Role class, tables, data, etc. and everything seems to be working on that end as well.

The problem is that when I save a user and associate a Role, that association does not persist to the database.

I've added a RoleId (int16) column to the aspnet_Users table to match the Role table's Id (int16) column. I've tried using Save and SaveAndFlush without success.

Here's some code:

Role superUser = Role.First(r => r.name == "Super User");
User me = User.First(r => r.UserName == myUserName);
me.Role = superUser;
me.Save(); // Or: SaveAndFlush

When debugging, I can see the association on the objects when they're saved (i.e. me.Role is not null and has the right attributes/properties/etc.) However, when I look at the database, the RoleId value for that user is still NULL. (SaveAndFlush doesn't make a difference.)

What am I missing?

I've read somewhere on SO that extending the users table is usually done by adding another table and linking the two by a foreign key; I assume the classes would then use inheritance by composition for the new ExtendedUser class. Assuming I don't want to go that route, why isn't this working? Is it because of the specific ASP.NET MVC stored procedures et. all?

Some relevant mapping:

   [ActiveRecord("aspnet_Users", Mutable = false)]
    public class User : ActiveRecordLinqBase<User>
    {
        [PrimaryKey(PrimaryKeyType.Assigned)]
        public Guid UserId { get; set; }

        // ...

        [BelongsTo("RoleId", Cascade = CascadeEnum.SaveUpdate)]
        public Role Role { get; set; }
    }

    [ActiveRecord]
    public class Role : ActiveRecordLinqBase<Role>
    {
        [PrimaryKey]
        public int Id { get; set; }

        // ...

        [HasMany(Inverse = true)]
        public IList<User> Users { get; set; }

        [Property]
        public string Name { get; set; }
    }

Solution

  • Edit: mutable="false" - this clearly stands that entity is read only, which is the source of your problem.

    Immutable classes, mutable="false", may not be updated or deleted by the application. This allows NHibernate to make some minor performance optimizations.

    Also: I believe that you need to have cascading defined. You are not saving just the entity itself but also reference to other entity. Use attributes, fluent config or hbml to define this the way you need. Here are the cascading options:

    Here is what each cascade option means:

    • none - do not do any cascades, let the users handles them by themselves.
    • save-update - when the object is saved/updated, check the assoications and save/update any object that require it (including save/update the assoications in many-to-many scenario).
    • delete - when the object is deleted, delete all the objects in the assoication. delete-orphan - when the object is deleted, delete all the objects in the assoication. In addition to that, when an object is removed from the assoication and not assoicated with another object (orphaned), also delete it.
    • all - when an object is save/update/delete, check the assoications and save/update/delete all the objects found.
    • all-delete-orphan - when an object is save/update/delete, check the assoications and save/update/delete all the objects found. In additional to that, when an object is removed from the assoication and not assoicated with another object (orphaned), also delete it.

    You may want to read this article.