I am working on Fluent Nhibernate and I am getting the following error:
"Cannot insert the value NULL into column 'EmailAccountId', table 'NopCommerceNew123.dbo.QueuedEmail'; column does not allow nulls. INSERT fails.\\r\\nThe statement has been terminated."} could not insert: [Nop.Core.Domain.Messages.QueuedEmail][SQL: INSERT INTO QueuedEmail ([Priority], [From], FromName, [To], ToName, CC, Bcc, [Subject], Body, AttachmentFilePath, AttachmentFileName, CreatedOnUtc, SentTries, SentOnUtc, EmailAccountId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); select SCOPE_IDENTITY()]
Please let me know about the error in this.Thanks.
Here Are My Classes and mappings:
public partial class QueuedEmail : BaseEntity
{
/// <summary>
/// Gets or sets the priority
/// </summary>
public virtual int Priority { get; set; }
/// <summary>
/// Gets or sets the From property
/// </summary>
public virtual string From { get; set; }
/// <summary>
/// Gets or sets the FromName property
/// </summary>
public virtual string FromName { get; set; }
/// <summary>
/// Gets or sets the To property
/// </summary>
public virtual string To { get; set; }
/// <summary>
/// Gets or sets the ToName property
/// </summary>
public virtual string ToName { get; set; }
/// <summary>
/// Gets or sets the CC
/// </summary>
public virtual string CC { get; set; }
/// <summary>
/// Gets or sets the Bcc
/// </summary>
public virtual string Bcc { get; set; }
/// <summary>
/// Gets or sets the subject
/// </summary>
public virtual string Subject { get; set; }
/// <summary>
/// Gets or sets the body
/// </summary>
public virtual string Body { get; set; }
/// <summary>
/// Gets or sets the attachment file path (full file path)
/// </summary>
public virtual string AttachmentFilePath { get; set; }
/// <summary>
/// Gets or sets the attachment file name. If specified, then this file name will be sent to a recipient. Otherwise, "AttachmentFilePath" name will be used.
/// </summary>
public virtual string AttachmentFileName { get; set; }
/// <summary>
/// Gets or sets the date and time of item creation in UTC
/// </summary>
public virtual DateTime CreatedOnUtc { get; set; }
/// <summary>
/// Gets or sets the send tries
/// </summary>
public virtual int SentTries { get; set; }
/// <summary>
/// Gets or sets the sent date and time
/// </summary>
public virtual DateTime? SentOnUtc { get; set; }
/// <summary>
/// Gets or sets the used email account identifier
/// </summary>
public virtual int EmailAccountId { get; set; }
/// <summary>
/// Gets the email account
/// </summary>
public virtual EmailAccount EmailAccount { get; set; }
}
public partial class EmailAccount : BaseEntity
{
/// <summary>
/// Gets or sets an email address
/// </summary>
public virtual string Email { get; set; }
/// <summary>
/// Gets or sets an email display name
/// </summary>
public virtual string DisplayName { get; set; }
/// <summary>
/// Gets or sets an email host
/// </summary>
public virtual string Host { get; set; }
/// <summary>
/// Gets or sets an email port
/// </summary>
public virtual int Port { get; set; }
/// <summary>
/// Gets or sets an email user name
/// </summary>
public virtual string Username { get; set; }
/// <summary>
/// Gets or sets an email password
/// </summary>
public virtual string Password { get; set; }
/// <summary>
/// Gets or sets a value that controls whether the SmtpClient uses Secure Sockets Layer (SSL) to encrypt the connection
/// </summary>
public virtual bool EnableSsl { get; set; }
/// <summary>
/// Gets or sets a value that controls whether the default system credentials of the application are sent with requests.
/// </summary>
public virtual bool UseDefaultCredentials { get; set; }
public virtual ICollection<QueuedEmail> QueueEmail { get; set; }
/// <summary>
/// Gets a friendly email account name
/// </summary>
public virtual string FriendlyName
{
get
{
if (!String.IsNullOrWhiteSpace(this.DisplayName))
return this.Email + " (" + this.DisplayName + ")";
return this.Email;
}
}
public class QueuedEmailMap : ClassMap<QueuedEmail>
{
public QueuedEmailMap()
{
Table("QueuedEmail");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("Id");
Map(x => x.Priority).Column("[Priority]").Not.Nullable().Precision(10);
Map(x => x.From).Column("[From]").Not.Nullable().Length(500);
Map(x => x.FromName).Column("FromName").Length(500);
Map(x => x.To).Column("[To]").Not.Nullable().Length(500);
Map(x => x.ToName).Column("ToName").Length(500);
Map(x => x.CC).Column("CC").Length(500);
Map(x => x.Bcc).Column("Bcc").Length(500);
Map(x => x.Subject).Column("[Subject]").Length(1000);
Map(x => x.Body).Column("Body");
Map(x => x.AttachmentFilePath).Column("AttachmentFilePath");
Map(x => x.AttachmentFileName).Column("AttachmentFileName");
Map(x => x.CreatedOnUtc).Column("CreatedOnUtc").Not.Nullable();
Map(x => x.SentTries).Column("SentTries").Not.Nullable().Precision(10);
Map(x => x.SentOnUtc).Column("SentOnUtc");
//References(x => x.EmailAccount).Class<EmailAccount>().Columns("EmailAccountId");
References(x => x.EmailAccount).Column("EmailAccountId").Not.Nullable().Cascade.All();
}
}
public class EmailAccountMap : ClassMap<EmailAccount>
{
public EmailAccountMap()
{ Table("EmailAccount");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("Id");
Map(x => x.Email).Column("Email").Not.Nullable().Length(255);
Map(x => x.DisplayName).Column("DisplayName").Length(255);
Map(x => x.Host).Column("Host").Not.Nullable().Length(255);
Map(x => x.Port).Column("Port").Not.Nullable().Precision(10);
Map(x => x.Username).Column("Username").Not.Nullable().Length(255);
Map(x => x.Password).Column("Password").Not.Nullable().Length(255);
Map(x => x.EnableSsl).Column("EnableSsl").Not.Nullable();
Map(x => x.UseDefaultCredentials).Column("UseDefaultCredentials").Not.Nullable();
}
}
The solution here would be to assign EmailAccount
of the QueuedEmail
instance, when adding it into the collection of QueuedEmails . This should be the code:
// method somewhere in the 'EmailAccount' definiton
public void AddEmail(QueuedEmail email)
{
this.QueueEmail.Add(email)
email.EmailAccount = this;
}
this will correctly assign the value "EmailAccount" into the column "EmailAccountId" during the INSERT.
The reason is: we declared the collection of QueueEmail
as inverse
HasMany<QueuedEmail>(x => x.QueueEmail)
.KeyColumn("EmailAccountId")
.Inverse() // here we say inverse
.Cascade.All();
And inverse is a sign for NHibernate: the child does know about its parent reference - child will care about self (because it has enough information) . And with the adjustment above (assigning the parent) all will work.
"not-null property references a null or transient value QueuedEmail.EmailAccount."
The problem is, that when we call: session.Save(queuedEmail)
the queuedEmail instance must have set the reference EmailAccount
. It is not enough to set integer EmailAccountId
! Why? because it is not mapped. And there is in fact solution
So, if we always can be sure, that we have the EmailAccountId
, we can use this mapping:
public class QueuedEmailMap : ClassMap<QueuedEmail>
{
public QueuedEmailMap()
{
...
// this property will be WRITABLE
Map(x => x.x.EmailAccountId)
.Column("EmailAccountId")
// this one will be readonly
References(x => x.EmailAccount)
.Column("EmailAccountId")
.Not.Nullable()
.Cascade.All()
.Not.Insert() // this is the setting
.Not.Update()
;
...
From this moment, we can set just the reference Id and all will work.
NOTE: I do also use the doubled mapping (Id and Reference), but the readonly is the int Id
You can add the property twice like Radim says. Or delete the property EmailAccountId
from QueuedEmail
class and just add this to your mapping:
public class EmailAccountMap : ClassMap<EmailAccount>
{
public EmailAccountMap()
{
// your code
HasMany<QueuedEmail>(x => x.QueueEmail)
.KeyColumn("EmailAccountId")
.Inverse()
.Cascade.All();
}
}
public class QueuedEmailMap : ClassMap<QueuedEmail>
{
public QueuedEmailMap()
{
// your code
References(x => x.EmailAccount)
.Column("EmailAccountId")
.Not.Nullable();
}
}
Don't forget call:
session.Save(emailAccount)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.