流利的Nhibernate中的一对多映射

时间:2014-05-13 14:34:53

标签: c# nhibernate fluent-nhibernate nhibernate-mapping fluent-nhibernate-mapping

我正在使用Fluent Nhibernate,我收到以下错误:

  

"无法将值NULL插入列' EmailAccountId',table' NopCommerceNew123.dbo.QueuedEmail&#39 ;;列不允许空值。 INSERT失败。\ r \ n语句已终止。"}无法插入:[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(?,?,?,?,?,?,?,?,?,?,? ,?,?,?,?);选择SCOPE_IDENTITY()]

请告诉我这个错误。谢谢。

这是我的类和映射:

QueueEmail.cs

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; }
}

EmailAccount.cs

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;
        }
    }

QueuedEmailMap.cs:

 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();
        }
    }

EmailAccountMap.cs:

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();

    }
}

2 个答案:

答案 0 :(得分:2)

此处的解决方案是在将EmailAccount实例添加到 QueuedEmails 的集合中时分配QueuedEmail。这应该是代码:

// method somewhere in the 'EmailAccount' definiton
public void AddEmail(QueuedEmail email)
{
    this.QueueEmail.Add(email)
    email.EmailAccount = this;
}

这将正确分配值&#34; EmailAccount&#34;进入专栏&#34; EmailAccountId&#34; INSERT期间。

原因是:我们将QueueEmail的集合声明为反向

HasMany<QueuedEmail>(x => x.QueueEmail)
  .KeyColumn("EmailAccountId")
  .Inverse() // here we say inverse
  .Cascade.All(); 

是NHibernate的标志:孩子确实知道关于其父引用 - 孩子会关心关于自我(因为它有足够的信息)。通过(分配父母)上面的调整,一切都会有效。

编辑:如何解决下一个问题:

  

&#34; not-null属性引用空值或瞬态值QueuedEmail.EmailAccount。&#34;

问题是,当我们致电:session.Save(queuedEmail)时, queuedEmail 实例必须设置引用EmailAccount。设置整数 EmailAccountId是不够的!为什么?因为它没有映射。实际上有解决方案

所以,如果我们总能确定,我们有EmailAccountId,我们就可以使用这种映射:

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()
          ;
    ...

从这一刻起,我们可以只设置参考ID,并且一切都可以。

注意:我也使用doubled映射(Id和Reference),但readonly是int Id

答案 1 :(得分:0)

你可以像Radim说的那样两次添加属性。或者从EmailAccountId类中删除属性QueuedEmail,然后将其添加到您的映射中:

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();
    }
}

别忘了打电话:

session.Save(emailAccount)