每个子类的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>();
}));
}
);
}
}