每个子类的NHibernate表会导致无意义的INSERT语句-我做错了什么?

每个子类的NHibernate表会导致无意义的INSERT语句-我做错了什么?,nhibernate,nhibernate-mapping,mapping-by-code,discriminator,table-per-subclass,Nhibernate,Nhibernate Mapping,Mapping By Code,Discriminator,Table Per Subclass,我拥有以下实体: public abstract class User : IIdentity { private readonly UserType _userType; public virtual int EntitySK { get; set; } public virtual int TenantSK { get; set; } public abstract string Name { get; set; } public virtual P

我拥有以下实体:

public abstract class User : IIdentity
{
    private readonly UserType _userType;

    public virtual int EntitySK { get; set; }
    public virtual int TenantSK { get; set; }
    public abstract string Name { get; set; }
    public virtual PublicKey PublicKey { get; set; }
    public abstract string AuthenticationType { get; set; }
    public virtual bool IsAuthenticated { get; protected internal set; }
    public virtual bool LoginEnabled { get; set; }
    public virtual bool LockedOut { get; set; }
    public virtual int NumberOfFailedLoginAttempts { get; set; }

    // Hibernate requires this constructor
    protected User()
    {
        this._userType = this is PersonUser ? Models.UserType.Person : Models.UserType.Client;
        this.LoginEnabled = true;
    }

    protected User(UserType userType)
    {
        this._userType = userType;
        this.LoginEnabled = true;
    }

    public virtual UserType UserType
    {
        get { return this._userType; }
        set
        {
            if(value != this._userType)
                throw new InvalidOperationException("Attempted to load " + value + " into " + this._userType + "User.");
        }
    }
}

public class PersonUser : User
{
    public virtual string Domain { get; set; }
    public override string Name { get; set; }
    public virtual byte[] Password { get; set; }
    public virtual byte[] Pepper { get; set; }
    public virtual string EmailAddress { get; set; }
    public virtual int PersonSK { get; set; }
    public override string AuthenticationType { get; set; }

    public PersonUser() : base(UserType.Person) { }
}

public class ClientUser : User
{
    public override string Name { get; set; }
    public virtual string SharedSecret { get; set; }
    public virtual ISet<string> Scopes { get; set; }
    public virtual ISet<GrantType> AuthorizedGrantTypes { get; set; }
    public virtual ISet<Uri> RegisteredRedirectUris { get; set; }
    public virtual int AuthorizationCodeValiditySeconds { get; set; }
    public virtual int AccessTokenValiditySeconds { get; set; }

    public ClientUser() : base(UserType.Client) { }
}
重要的是,请查看生成的SQL:

INSERT INTO Authentication_Users (TenantSK, DisplayName, PublicKey, LoginEnabled, LockedOut, NumberOfFailedLoginAttempts, Username, AuthenticationType, UserType) VALUES (?, ?, ?, ?, ?, ?, ?, ?, '1')
这毫无意义。它与映射完全不对应。它在一个表的insert语句中包含来自三个不同表的列。它有来自
PersonUser
ClientUser
的列(这不可能),它用不存在的参数索引绑定参数,甚至不包括我设置的所有属性

我已经玩了好几个小时了,没有任何进展。我在这里完全不知所措。这根本没有任何意义。有人见过这个吗?知道发生了什么吗


编辑我忘了提一下:我在这里使用鉴别器是因为我想通过ID获取一个通用的
用户
,它会返回正确的
个人用户
客户用户
,这取决于它是哪种类型。

映射存在一些问题

a) 您将UserType映射为属性,但也将其用作鉴别器。但是用户类型值是由nhibernate生成的,因为鉴别器的使用。。。因此,您可以定义要生成的属性

this.Property(u => u.UserType,
    m =>
    {
        m.Column("UserType");
        m.NotNullable(true);
        m.Generated(PropertyGeneration.Always); // this should fix it for user type
        m.Type<EnumCustomType<UserType>>();
    });
b) 仅在子类中映射基类的
Name
属性,并且尝试将该属性映射到子类表中的不同列。 不知道这是否可能,通常您必须将基类的所有属性映射到基类表,或者将属性移动到子类中


要解决这个问题,只需从子类映射中删除到
Name
的映射,并将其移动到基类映射。

在MichaC的帮助下,这就是最终有效的代码

实体:

public abstract class User : IIdentity
{
    // necessary because the property is read-only
    private readonly UserType _userType;
    // necessary because the property needs to default to true
    private bool _loginEnabled = true;

    //-------- These properties are mapped to database columns --------//
    public virtual int ObjectId { get; set; }
    public virtual int? TenantId { get; set; }
    public virtual PublicKey PublicKey { get; set; }
    public virtual bool LoginEnabled { get { return this._loginEnabled; } set { this._loginEnabled = value; } }
    public virtual bool LockedOut { get; set; }
    public virtual int NumberOfFailedLoginAttempts { get; set; }

    //-------- These properties are NOT mapped to database columns --------//
    public abstract string Name { get; set; }
    public abstract string AuthenticationType { get; set; }
    public virtual bool IsAuthenticated { get; protected internal set; }
    public virtual UserType UserType
    {
        get { return this._userType; }
        set { throw new InvalidOperationException("Property UserType is read-only."); }
    }

    ...
}

public class PersonUser : User
{
    //-------- These properties are mapped to database columns --------//
    public virtual string Domain { get; set; }
    protected internal virtual string Username { get { return this.Name; } set { this.Name = value; } }
    public virtual byte[] Password { get; set; }
    public virtual byte[] Pepper { get; set; }
    public virtual string EmailAddress { get; set; }
    public virtual int PersonSK { get; set; }
    protected internal virtual string AuthenticationStrategy
    {
        get { return this.AuthenticationType; }
        set { this.AuthenticationType = value; }
    }

    //-------- These properties are NOT mapped to database columns --------//
    public override string Name { get; set; }
    public override string AuthenticationType { get; set; }
}

public class ClientUser : User
{
    //-------- These properties are mapped to database columns --------//
    protected internal virtual string DisplayName { get { return this.Name; } set { this.Name = value; } }
    public virtual string SharedSecret { get; set; }
    public virtual ISet<string> Scopes { get; set; }
    public virtual ISet<GrantType> AuthorizedGrantTypes { get; set; }
    public virtual ISet<Uri> RegisteredRedirectUris { get; set; }
    public virtual int AuthorizationCodeValiditySeconds { get; set; }
    public virtual int AccessTokenValiditySeconds { get; set; }

    //-------- These properties are NOT mapped to database columns --------//
    public override string Name { get; set; }
    public override string AuthenticationType
    {
        get { return AuthorizationHeaderProtocol.SignatureClientCredentials; }
        set { throw new InvalidOperationException("Cannot change the authentication type for a ClientUser."); }
    }
}
公共抽象类用户:IIdentity
{
//因为该属性是只读的,所以是必需的
私有只读用户类型_UserType;
//必需,因为属性需要默认为true
private bool_loginEnabled=true;
//--------这些属性映射到数据库列--------//
公共虚拟int ObjectId{get;set;}
公共虚拟int?租户{get;set;}
公共虚拟公钥公钥{get;set;}
公共虚拟bool LoginEnabled{get{返回此值。_LoginEnabled;}设置{this。_LoginEnabled=value;}}
公共虚拟布尔锁定输出{get;set;}
公共虚拟int NumberOfFailedLoginAttests{get;set;}
//--------这些属性未映射到数据库列--------//
公共抽象字符串名称{get;set;}
公共抽象字符串身份验证类型{get;set;}
公共虚拟布尔值已验证{get;受保护的内部集;}
公共虚拟用户类型用户类型
{
获取{返回此。\u userType;}
设置{抛出新的InvalidOperationException(“属性UserType为只读。”);}
}
...
}
公共类用户:用户
{
//--------这些属性映射到数据库列--------//
公共虚拟字符串域{get;set;}
受保护的内部虚拟字符串用户名{get{返回this.Name;}set{this.Name=value;}}
公共虚拟字节[]密码{get;set;}
公共虚拟字节[]{get;set;}
公共虚拟字符串EmailAddress{get;set;}
公共虚拟整数PersonSK{get;set;}
受保护的内部虚拟字符串身份验证策略
{
获取{返回this.AuthenticationType;}
设置{this.AuthenticationType=value;}
}
//--------这些属性未映射到数据库列--------//
公共重写字符串名称{get;set;}
公共重写字符串身份验证类型{get;set;}
}
公共类ClientUser:User
{
//--------这些属性映射到数据库列--------//
受保护的内部虚拟字符串DisplayName{get{返回this.Name;}set{this.Name=value;}}
公共虚拟字符串SharedSecret{get;set;}
公共虚拟ISet作用域{get;set;}
公共虚拟ISet AuthorizedGrantTypes{get;set;}
公共虚拟ISet RegisteredDirectURI{get;set;}
公共虚拟整数授权CodeValiditySeconds{get;set;}
公共虚拟int-AccessTokenValiditySeconds{get;set;}
//--------这些属性未映射到数据库列--------//
公共重写字符串名称{get;set;}
公共重写字符串AuthenticationType
{
获取{return AuthorizationHeaderProtocol.SignatureClientCredentials;}
设置{抛出新的InvalidOperationException(“无法更改ClientUser的身份验证类型。”);}
}
}
映射:

public class UserMapping : ClassMapping<User>
{
    public UserMapping()
    {
        LogManager.GetLogger().Info("Initialized User mapping.");

        this.Table("Authentication_Users");
        this.Id(u => u.ObjectId,
            m => {
                m.Column("UserId");
                m.Generator(Generators.Identity);
                m.UnsavedValue(0);
            });
        this.Property(u => u.TenantId,
            m => {
                m.Column("TenantId");
                m.NotNullable(false);
            });
        this.Property(u => u.PublicKey,
            m => {
                m.Column("PublicKey");
                m.Type<PublicKeyCustomType>();
                m.NotNullable(false);
                m.Lazy(true);
            });
        this.Property(u => u.LoginEnabled,
            m => {
                m.Column("LoginEnabled");
                m.NotNullable(true);
            });
        this.Property(u => u.LockedOut,
            m => {
                m.Column("LockedOut");
                m.NotNullable(true);
            });
        this.Property(u => u.NumberOfFailedLoginAttempts,
            m => {
                m.Column("NumberOfFailedLoginAttempts");
                m.NotNullable(true);
            });
        this.Discriminator(d => d.Column("UserType"));
    }
}

public class PersonUserMapping : SubclassMapping<PersonUser>
{
    public PersonUserMapping()
    {
        LogManager.GetLogger().Info("Initialized PersonUser mapping.");

        this.DiscriminatorValue((int)UserType.Person);
        this.Join(
            "PersonUser",
            j =>
            {
                j.Table("Authentication_Users_PersonUsers");
                j.Key(m => {
                        m.Column("UserId");
                        m.NotNullable(true);
                        m.OnDelete(OnDeleteAction.Cascade);
                        m.Unique(true);
                        m.Update(false);
                    });
                j.Property(u => u.Domain,
                    m => {
                        m.Column("DomainName");
                        m.NotNullable(false);
                    });
                j.Property("Username", // protected internal, see NH-3485
                    m => {
                        m.Column("Username");
                        m.NotNullable(true);
                    });
                j.Property(u => u.Password,
                    m => {
                        m.Column("Password");
                        m.NotNullable(false);
                        m.Lazy(true);
                    });
                j.Property(u => u.Pepper,
                    m => {
                        m.Column("Pepper");
                        m.NotNullable(false);
                        m.Lazy(true);
                    });
                j.Property(u => u.EmailAddress,
                    m => {
                        m.Column("EmailAddress");
                        m.NotNullable(false);
                    });
                j.Property(u => u.PersonSK,
                    m => {
                        m.Column("PersonSK");
                        m.NotNullable(false);
                    });
                j.Property("AuthenticationStrategy", // protected internal, see NH-3485
                    m => {
                        m.Column("AuthenticationType");
                        m.NotNullable(true);
                    });
            }
        );
    }
}

public class ClientUserMapping : SubclassMapping<ClientUser>
{
    public ClientUserMapping()
    {
        LogManager.GetLogger().Info("Initialized ClientUser mapping.");

        this.DiscriminatorValue((int)UserType.Client);
        this.Join(
            "ClientUser",
            j =>
            {
                j.Table("Authentication_Users_ClientUsers");
                j.Key(m => {
                        m.Column("UserId");
                        m.NotNullable(true);
                        m.OnDelete(OnDeleteAction.Cascade);
                        m.Unique(true);
                        m.Update(false);
                    });
                j.Property("DisplayName", // protected internal, see NH-3485
                    m => {
                        m.Column("DisplayName");
                        m.NotNullable(true);
                    });
                j.Property(u => u.SharedSecret,
                    m => {
                        m.Column("SharedSecret");
                        m.NotNullable(true);
                    });
                j.Property(u => u.AuthorizationCodeValiditySeconds,
                    m => {
                        m.Column("AuthorizationCodeValiditySeconds");
                        m.NotNullable(true);
                    });
                j.Property(u => u.AccessTokenValiditySeconds,
                    m => {
                        m.Column("AccessTokenValiditySeconds");
                        m.NotNullable(true);
                    });

                j.Set(u => u.Scopes,
                    s => {
                        s.Fetch(CollectionFetchMode.Join);
                        s.Lazy(CollectionLazy.Lazy);
                        s.Table("Authentication_Users_ClientUsers_Scopes");
                        s.Key(m => {
                            m.Column("UserId");
                            m.NotNullable(true);
                        });
                    },
                    r => r.Element(m => {
                            m.Column("Scope");
                            m.NotNullable(true);
                            m.Unique(true);
                    }));

                j.Set(u => u.AuthorizedGrantTypes,
                    s => {
                        s.Fetch(CollectionFetchMode.Join);
                        s.Lazy(CollectionLazy.Lazy);
                        s.Table("Authentication_Users_ClientUsers_AuthorizedGrantTypes");
                        s.Key(m => {
                            m.Column("UserId");
                            m.NotNullable(true);
                        });
                    },
                    r => r.Element(m => {
                            m.Column("GrantType");
                            m.NotNullable(true);
                            m.Unique(true);
                            m.Type<EnumCustomType<GrantType>>();
                    }));

                j.Set(u => u.RegisteredRedirectUris,
                    s => {
                        s.Fetch(CollectionFetchMode.Join);
                        s.Lazy(CollectionLazy.Lazy);
                        s.Table("Authentication_Users_ClientUsers_RegisteredRedirectUris");
                        s.Key(m => {
                            m.Column("UserId");
                            m.NotNullable(true);
                        });
                    },
                    r => r.Element(m => {
                            m.Column("Uri");
                            m.NotNullable(true);
                            m.Unique(true);
                            m.Type<UriCustomType>();
                    }));
            }
        );
    }
}
公共类用户映射:类映射
{
公共用户映射()
{
LogManager.GetLogger().Info(“初始化的用户映射”);
此表(“身份验证用户”);
this.Id(u=>u.ObjectId,
m=>{
m、 列(“用户ID”);
m、 生成器(生成器.标识);
m、 未保存值(0);
});
this.Property(u=>u.TenantId,
m=>{
m、 列(“租户”);
m、 不可为空(false);
});
this.Property(u=>u.PublicKey,
m=>{
m、 列(“公钥”);
m、 类型();
m、 不可为空(false);
m、 懒惰(真);
});
this.Property(u=>u.logineEnabled,
m=>{
m、 列(“登录启用”);
m、 不可为空(true);
});
this.Property(u=>u.LockedOut,
m=>{
m、 列(“锁定输出”);
m、 不可为空(true);
});
此.Property(u=>u.NumberOfFailedLoginAttents,
m=>{
m、 列(“NumberOfFailedLoginAttents”);
m、 NotNullabl
    public virtual UserType UserType
    {
        get;
        protected internal set;
    }
public abstract class User : IIdentity
{
    // necessary because the property is read-only
    private readonly UserType _userType;
    // necessary because the property needs to default to true
    private bool _loginEnabled = true;

    //-------- These properties are mapped to database columns --------//
    public virtual int ObjectId { get; set; }
    public virtual int? TenantId { get; set; }
    public virtual PublicKey PublicKey { get; set; }
    public virtual bool LoginEnabled { get { return this._loginEnabled; } set { this._loginEnabled = value; } }
    public virtual bool LockedOut { get; set; }
    public virtual int NumberOfFailedLoginAttempts { get; set; }

    //-------- These properties are NOT mapped to database columns --------//
    public abstract string Name { get; set; }
    public abstract string AuthenticationType { get; set; }
    public virtual bool IsAuthenticated { get; protected internal set; }
    public virtual UserType UserType
    {
        get { return this._userType; }
        set { throw new InvalidOperationException("Property UserType is read-only."); }
    }

    ...
}

public class PersonUser : User
{
    //-------- These properties are mapped to database columns --------//
    public virtual string Domain { get; set; }
    protected internal virtual string Username { get { return this.Name; } set { this.Name = value; } }
    public virtual byte[] Password { get; set; }
    public virtual byte[] Pepper { get; set; }
    public virtual string EmailAddress { get; set; }
    public virtual int PersonSK { get; set; }
    protected internal virtual string AuthenticationStrategy
    {
        get { return this.AuthenticationType; }
        set { this.AuthenticationType = value; }
    }

    //-------- These properties are NOT mapped to database columns --------//
    public override string Name { get; set; }
    public override string AuthenticationType { get; set; }
}

public class ClientUser : User
{
    //-------- These properties are mapped to database columns --------//
    protected internal virtual string DisplayName { get { return this.Name; } set { this.Name = value; } }
    public virtual string SharedSecret { get; set; }
    public virtual ISet<string> Scopes { get; set; }
    public virtual ISet<GrantType> AuthorizedGrantTypes { get; set; }
    public virtual ISet<Uri> RegisteredRedirectUris { get; set; }
    public virtual int AuthorizationCodeValiditySeconds { get; set; }
    public virtual int AccessTokenValiditySeconds { get; set; }

    //-------- These properties are NOT mapped to database columns --------//
    public override string Name { get; set; }
    public override string AuthenticationType
    {
        get { return AuthorizationHeaderProtocol.SignatureClientCredentials; }
        set { throw new InvalidOperationException("Cannot change the authentication type for a ClientUser."); }
    }
}
public class UserMapping : ClassMapping<User>
{
    public UserMapping()
    {
        LogManager.GetLogger().Info("Initialized User mapping.");

        this.Table("Authentication_Users");
        this.Id(u => u.ObjectId,
            m => {
                m.Column("UserId");
                m.Generator(Generators.Identity);
                m.UnsavedValue(0);
            });
        this.Property(u => u.TenantId,
            m => {
                m.Column("TenantId");
                m.NotNullable(false);
            });
        this.Property(u => u.PublicKey,
            m => {
                m.Column("PublicKey");
                m.Type<PublicKeyCustomType>();
                m.NotNullable(false);
                m.Lazy(true);
            });
        this.Property(u => u.LoginEnabled,
            m => {
                m.Column("LoginEnabled");
                m.NotNullable(true);
            });
        this.Property(u => u.LockedOut,
            m => {
                m.Column("LockedOut");
                m.NotNullable(true);
            });
        this.Property(u => u.NumberOfFailedLoginAttempts,
            m => {
                m.Column("NumberOfFailedLoginAttempts");
                m.NotNullable(true);
            });
        this.Discriminator(d => d.Column("UserType"));
    }
}

public class PersonUserMapping : SubclassMapping<PersonUser>
{
    public PersonUserMapping()
    {
        LogManager.GetLogger().Info("Initialized PersonUser mapping.");

        this.DiscriminatorValue((int)UserType.Person);
        this.Join(
            "PersonUser",
            j =>
            {
                j.Table("Authentication_Users_PersonUsers");
                j.Key(m => {
                        m.Column("UserId");
                        m.NotNullable(true);
                        m.OnDelete(OnDeleteAction.Cascade);
                        m.Unique(true);
                        m.Update(false);
                    });
                j.Property(u => u.Domain,
                    m => {
                        m.Column("DomainName");
                        m.NotNullable(false);
                    });
                j.Property("Username", // protected internal, see NH-3485
                    m => {
                        m.Column("Username");
                        m.NotNullable(true);
                    });
                j.Property(u => u.Password,
                    m => {
                        m.Column("Password");
                        m.NotNullable(false);
                        m.Lazy(true);
                    });
                j.Property(u => u.Pepper,
                    m => {
                        m.Column("Pepper");
                        m.NotNullable(false);
                        m.Lazy(true);
                    });
                j.Property(u => u.EmailAddress,
                    m => {
                        m.Column("EmailAddress");
                        m.NotNullable(false);
                    });
                j.Property(u => u.PersonSK,
                    m => {
                        m.Column("PersonSK");
                        m.NotNullable(false);
                    });
                j.Property("AuthenticationStrategy", // protected internal, see NH-3485
                    m => {
                        m.Column("AuthenticationType");
                        m.NotNullable(true);
                    });
            }
        );
    }
}

public class ClientUserMapping : SubclassMapping<ClientUser>
{
    public ClientUserMapping()
    {
        LogManager.GetLogger().Info("Initialized ClientUser mapping.");

        this.DiscriminatorValue((int)UserType.Client);
        this.Join(
            "ClientUser",
            j =>
            {
                j.Table("Authentication_Users_ClientUsers");
                j.Key(m => {
                        m.Column("UserId");
                        m.NotNullable(true);
                        m.OnDelete(OnDeleteAction.Cascade);
                        m.Unique(true);
                        m.Update(false);
                    });
                j.Property("DisplayName", // protected internal, see NH-3485
                    m => {
                        m.Column("DisplayName");
                        m.NotNullable(true);
                    });
                j.Property(u => u.SharedSecret,
                    m => {
                        m.Column("SharedSecret");
                        m.NotNullable(true);
                    });
                j.Property(u => u.AuthorizationCodeValiditySeconds,
                    m => {
                        m.Column("AuthorizationCodeValiditySeconds");
                        m.NotNullable(true);
                    });
                j.Property(u => u.AccessTokenValiditySeconds,
                    m => {
                        m.Column("AccessTokenValiditySeconds");
                        m.NotNullable(true);
                    });

                j.Set(u => u.Scopes,
                    s => {
                        s.Fetch(CollectionFetchMode.Join);
                        s.Lazy(CollectionLazy.Lazy);
                        s.Table("Authentication_Users_ClientUsers_Scopes");
                        s.Key(m => {
                            m.Column("UserId");
                            m.NotNullable(true);
                        });
                    },
                    r => r.Element(m => {
                            m.Column("Scope");
                            m.NotNullable(true);
                            m.Unique(true);
                    }));

                j.Set(u => u.AuthorizedGrantTypes,
                    s => {
                        s.Fetch(CollectionFetchMode.Join);
                        s.Lazy(CollectionLazy.Lazy);
                        s.Table("Authentication_Users_ClientUsers_AuthorizedGrantTypes");
                        s.Key(m => {
                            m.Column("UserId");
                            m.NotNullable(true);
                        });
                    },
                    r => r.Element(m => {
                            m.Column("GrantType");
                            m.NotNullable(true);
                            m.Unique(true);
                            m.Type<EnumCustomType<GrantType>>();
                    }));

                j.Set(u => u.RegisteredRedirectUris,
                    s => {
                        s.Fetch(CollectionFetchMode.Join);
                        s.Lazy(CollectionLazy.Lazy);
                        s.Table("Authentication_Users_ClientUsers_RegisteredRedirectUris");
                        s.Key(m => {
                            m.Column("UserId");
                            m.NotNullable(true);
                        });
                    },
                    r => r.Element(m => {
                            m.Column("Uri");
                            m.NotNullable(true);
                            m.Unique(true);
                            m.Type<UriCustomType>();
                    }));
            }
        );
    }
}