【问题标题】:Wrong column name weird issue in Entity Framework实体框架中错误的列名奇怪问题
【发布时间】:2020-01-05 01:23:29
【问题描述】:

我遇到这个问题已经有一段时间了,老实说,我自己也对此感到困惑,所以如果我没有成功地解释它,请原谅我。

我正在尝试将一些数据插入一个名为CommunicationAttachment 的表中,该表与Communication 关联为一对多关系;每个通信都可以有很多附件。

事情是我得到了:

UpdateException:列名无效:“Communication_CommunicationId

当我尝试插入附件列表时。

请注意,我使用的是存储库模式,但我什至尝试了正常方式,但问题没有解决。

我尝试跟踪数据库上发生的事务,发现它使用Insert 语句发送Communication_CommunicationId,但没有这样的列。我很确定我没有发送这样的专栏。

这是我的代码(添加新的Communication 时会发生这种情况);首先我打电话给CasefileAttachments从他们那里复制,CommunicationsCaseFiles相关:

public List<CorrespondenceAttachment> GetCaseFileAttachments(List<Guid> CorrespondenceAttachmentIds) 
{
    List<CorrespondenceAttachment> originalAttachments = new List<CorrespondenceAttachment>();

    foreach (var item in CorrespondenceAttachmentIds)
    {
        var attachment = QueryData.Query<CorrespondenceAttachment>().Where(att => att.CorrespondenceAttachmentID == item).FirstOrDefault();
        originalAttachments.Add(attachment);
    }

    return originalAttachments;
}

然后我复制CaseFileAttachments 并创建CommunicationAttachments 的新对象:

public List<CommunicationAttachment> CopyCaseFileAttachmentsToCommunication(List<CorrespondenceAttachment> originalAttachments,Guid communicationId)
{
    var communicationAttachments = new List<CommunicationAttachment>();

    if (originalAttachments.Any())
    {
        foreach (var attachmentRef in originalAttachments)
        {
            var CommunicationAttachmentId = Guid.NewGuid();

            communicationAttachments.Add(new CommunicationAttachment()
            {
                CommunicationAttachmentId = CommunicationAttachmentId,
                DmsFileId = CommunicationAttachmentId,
                CommunicationId = communicationId,
                AttachmentTitle = attachmentRef.AttachmentTitle,
                MimeType = attachmentRef.MimeType,
                NewVersionID = null,
                UploadDate = DateTime.Now,
                Size = attachmentRef.Size,
                Version = "0001",
                AttachmentsGroupId = attachmentRef.AttachmentsGroupId,
                DocumentId = attachmentRef.DocumentId,
                RelativePath = attachmentRef.RelativePath,
                Extension = attachmentRef.Extension,
                AttachmentSubject = attachmentRef?.AttachmentSubject,
                ExternalContactID = attachmentRef?.ExternalContactID,
                AttachmentNumber = string.IsNullOrEmpty(attachmentRef?.AttachmentNumber) ? null : attachmentRef.AttachmentNumber,
                TemplatedmsId = attachmentRef.TemplatedmsId,
                State = eSense.Framework.Data.ObjectState.Added,
            });
        }
    }

    return communicationAttachments;
}

上面的方法是这样调用的:

public void AddNewCommunication(CommunicationDto communicationDto)
{
    var communication = communicationDto

   if (communicationDto.CommunicationAttachmentIdList.Any())
   {
       caseFileAttachments = GetCaseFileAttachments(communicationDto.CommunicationAttachmentIdList);

       if (caseFileAttachments.Any())
       {
           commAttachments = CopyCaseFileAttachmentsToCommunication(caseFileAttachments, communication.CommunicationId);
       }
   }

   communication.Attachments = commAttachments;

   Save(communication)
}

那么我得到错误的列名可能是什么问题?

这是CommunicationCommunicationAttachment之间的关系

注意我只添加了重要字段,所以如果声明与实体不匹配,请不要打扰

通信实体:

public class Communication : BaseEntity
{
    public Communication()
    {
        Attachments = new HashSet<CommunicationAttachment>();
    }

    [Key]
    public Guid CommunicationId { get; set; }

    public string Subject { get; set; }

    public string CommunicationNumber { get; set; }

    public virtual ICollection<CommunicationAttachment> Attachments { get; set; }

    public DateTime DateCreated { get; set; }

    public Guid? PreviousCommunicationId { get; set; }
    [ForeignKey("PreviousCommunicationId")]
    public virtual Communication PreviousCommunication { get; set; }

}

CommunicationAttachment 实体:

public class CommunicationAttachment : AttachmentBaseWithDelegation<Guid>
{
    public override Guid PrimaryId
    {
        get
        {
            return this.CommunicationAttachmentId;
        }
    }

    public CommunicationAttachment()
    {
    }

    [Key]
    public Guid CommunicationAttachmentId { get; set; }

    private string _attachmentNumber;

    public string AttachmentNumber { get; set; }

    [ForeignKey("NewVersionID")]
    public virtual CommunicationAttachment CaseFileAttachmentNewerVersion { get; set; }

    public Guid CommunicationId { get; set; }
    [ForeignKey("CommunicationId")]
    public virtual Communication Communication { get; set; }


}

对不起,如果您发现我的问题很难理解,我自己也很困惑!

提前致谢。

【问题讨论】:

  • 1. SQL Profiler 上显示了什么? 2.如何在本地进行模型更改?迁移是否成功应用于本地开发数据库?错误的列名表明模型和模式不同步,即,甚至将 ORM 带入等式的全部意义。否则为什么还要使用 ORM。
  • 在 Profiler 中传递 CommunicationId 和 Communication_CommunicationId。是的,迁移已成功应用。我使用 ORM 与公司的同事相处。

标签: c# sql asp.net entity-framework


【解决方案1】:

这通常是实体之间的关系设置不正确的情况。如果通信的 PK 是“CommunicationId”,则 EF 似乎应该按照惯例解决这种关系。

我注意到您已经注释掉了一行以在新实体上设置 CommunicationId:

//CommunicationId = communicationId,

CommunicationAttachment 中有哪些字段?有通信 ID 吗?是否有通信导航属性?您正在使用哪些配置设置?

例如,使用流畅的配置,我会有类似的东西:

(通信实体配置)

如果 CommunicationAttachment 具有返回 Communication 的导航属性和名为 CommunicationId 的 FK 字段...

HasMany(x => x.CommunicationAttachments)
   .WithRequired(x => x.Communication)
   .HasForeignKey(x => x.CommunicationId);

如果附件实体具有导航属性,但实体中没有映射的 FK...

HasMany(x => x.CommunicationAttachments)
   .WithRequired(x => x.Communication)
   .Map(x => x.MapKey("CommunicationId"));

如果附件实体没有导航属性,但实体中有FK...

HasMany(x => x.CommunicationAttachments)
   .WithRequired()
   .HasForeignKey(x => x.CommunicationId);

或者最后,如果附件实体没有导航属性或映射的 FK...

如果附件实体没有导航属性,但实体中有FK...

HasMany(x => x.CommunicationAttachments)
   .WithRequired()
   .Map(x => x.MapKey("CommunicationId"));

我非常喜欢显式映射而不是约定,因为它非常清楚什么映射到什么以及如何映射,以解决潜在的映射冲突。如果其他类似的关系似乎正在发挥作用,而只是这个关系正在发挥作用,我会在字段名称中寻找可能的拼写错误。使用上述映射集合,设置Communcation.CommunicationAttachments.Add(attachment) 应该是在附件上设置外键/相关实体,而无需手动显式设置外键或相关实体。

补充说明:

从您的示例中,我看到您正在使用 Guid.NewGuid() 在客户端手动设置主键。通常最好让数据库管理 PK 生成,让 EF 管理 FK 分配,以确保相关实体自动将 FK 获取到新插入的行。建议使用顺序 UUID,而不是 SQL 的 NewId() 或使用 Guid.NewGuid()。在 SQL Server 中,这是NewSequentialId()。对于客户端设置,您可以使用系统 DLL 调用来获取 ID 或简单地重新散列 Guid 字节来重现顺序 UUID 模式。见:Is there a .NET equalent to SQL Servers newsequentialid()

GUID 仍然具有相同的唯一性,字节被简单地排列成更加连续和实用的数据库索引,以减少页面碎片。缺点是 ID 更容易预测。根据您的数据库引擎,您可能希望根据数据库是针对低位字节还是高位字节进行索引优化来自定义算法。

将 GUID 用于数据库(顺序或其他方式)时,您应确保在数据库上有计划的索引维护作业。使用顺序 ID,此作业将运行得更快,并使索引表更紧凑。

【讨论】:

  • 注释代码用于测试目的。它现在没有评论。现在我将继续阅读。
  • 我更新了问题。请检查迁移
  • 我修复了模型构建器,一切顺利!太感谢了。你救了一条命。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-07
  • 2013-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多