views:

53

answers:

1

I'm getting a SQL query from NH, and it's generating a column that does not exist (thus producing an ADOException from NH).

SELECT roles0_.CreatedBy_id as CreatedBy4_1_, 
       roles0_.Id as Id1_, 
       roles0_.Id as Id18_0_, 
       roles0_.RoleDescription as RoleDesc2_18_0_, 
       roles0_.User_id as User3_18_0_ 
FROM [Role] roles0_ 
WHERE roles0_.CreatedBy_id=?

My problem is that I can't figure out where the CreatedBy column is coming from. Here's my class structure.

public abstract class DomainEntity
{
    public virtual int Id { get; set; }
}
public class User : DomainEntity
{
    /* all the regular stuff you'd expect */
    public virtual IList<Role> Roles { get; private set; }
}
public class Role : DomainEntity
{
    public virtual User User { get; set; }
    public virtual string RoleDescription { get; set; }
}

At app startup, I can inspect the configuration, and I can see the ColumnIterator for the Role class map. It has 4 items in the dictionary: id, user_id, roledescription, and createdby_id. So the query is legit based on the configuration, but I can't figure out the configuration based on the classes.

Yes, I have cleared my ASP.NET DLL cache, deleted the bin and obj directories, and anything else like that I could think of.

Edit #1

This is my Fluently.Configure statement

_configuration = Fluently.Configure()
    .Database(MsSqlConfiguration.MsSql2008.ConnectionString(_connectionString))
    .Mappings(m => m.AutoMappings.Add(GetPersistenceModel()))
    .BuildConfiguration();

And this is my call for GetPersistenceModel()

private static AutoPersistenceModel GetPersistenceModel()
{
    var configuration = new CustomAutomappingConfiguration();
    return AutoMap.AssemblyOf<User>(configuration)
        .IgnoreBase(typeof(DomainEntity))
        .UseOverridesFromAssemblyOf<UserMapOverride>()
        .Conventions.Setup(c =>
                               {
                                  c.Add<CustomHasManyConvention>();
                               });            
} 

My Custom config says to only map public autoproperties. This is so I can add other calculated properties to my domain entities. The user map override makes sure that the table name is [User], because I was getting SQL errors using just User. The Custom HasMany convention sets cascade all-delete-orphan for all has many relationships.

Edit #2

This gets even better. This is the column iterator after creating the configuration object, but before creating the session factory object.

before session factory

See? No createdby_id column in the list of mapped columns. This is the column iterator after creating the session factory object.

after session factory

And now there's a createdby_id column. I am really lost now.

Edit 3

OK, I think I'm onto something now.

I got a new requirement from my customer last week. That requirement was that they wanted to know who had created an assignment. So it has a new property as follows.

public class Assignment : DomainEntity {
  /* etc. */
  public virtual User CreatedBy { get; set; }
  /* etc. */
}

In my Assignment table, it now has a column like this.

[CreatedBy_id] INT NULL

And there's a FK to the User table on this new column.

If I comment out this property, everything works again. The SQL goes back to querying by user_id, exactly the way I would it expect it to be. Is there some type of override I can use to keep this from happening like this?

A: 

Well, I have a solution, but I don't know if it's the best answer, or if there's still a better solution out there.

I can add the following to my UserMapOverride class

public class UserMapOverride : IAutoMappingOverride<User> {
  public void Override(Automapping<User> mapping) {
    // Ensure that the string "User" is properly SQL-escaped. Without this line,
    // SQL queries are breaking.
    mapping.Table("[User]");

    // Force the FK to use the correct column.
    mapping.HasMany(x => x.Roles).KeyColumn("User_id");
  }
}

I'm hoping for someone to tell me that I'm doing something wrong with my AutoMapping, and I don't need to start throwing in overrides.

Jarrett Meyer

related questions