实体框架:跳过几列或从相关实体中选择为空

时间:2013-11-27 08:50:40

标签: c# sql entity-framework

我有三个实体,如下所示

public partial class Ticket
{
    public int TicketId { get; set; }
    ...
    public virtual ICollection<TicketComment> TicketComments { get; set; }
}

public partial class TicketComment
{
    public int CommentId { get; set; }
    public int TicketId { get; set; }
    ...
    public virtual ICollection<CommentAttachment> CommentAttachments { get; set; }
    public virtual Ticket Ticket { get; set; }
}

public partial class CommentAttachment
{
    public int FileId { get; set; }
    public int CommentID { get; set; }
    public string FileName { get; set; }
    public int FileSize { get; set; }
    public byte[] FileContents { get; set; }  // holds large data

    public virtual TicketComment TicketComment { get; set; }
}

此处每个票证可以有多个注释,每个注释可以有1个或0个附件。 我正在尝试使用以下代码急切加载给定票证的所有相关实体

var query = context.Tickets.Where(t => t.TicketId == ticketid)
             .Include(t => t.TicketComments.Select(c => c.CommentAttachments));

正确地完成工作。

只有问题在于,它还加载byte[] FileContents,它通常具有相当大的数据。我想避免它。

有什么方法可以为FileContents选择NULL或者完全跳过这一列?

我曾尝试过以下

var query = context.Tickets.Where(t => t.TicketId == ticketid)
            .Include(t => t.TicketComments
                .Select(c => c.CommentAttachments
                    .Select(ca => new CommentAttachment()
                    {
                        CommentID = ca.CommentID,
                        FileContents = null,
                        FileId = ca.FileId,
                        FileName = ca.FileName,
                        FileSize = ca.FileSize
                    })));

但是它给出了错误

The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties. Parameter name: path

避免加载FileContents列的任何想法?

2 个答案:

答案 0 :(得分:1)

public partial class CommentAttachment
{
    public int FileId { get; set; }
    public int CommentID { get; set; }
    public string FileName { get; set; }
    public int FileSize { get; set; }

    public virtual TicketComment TicketComment { get; set; }
}

public class FileContent
{
     FileContentId {get;set;}
     public int FileId { get; set; } // HERE IS THE FORGEIN KEY YOU HAVE TO UPDATE IT manually
     public byte[] FileContents { get; set; }  // holds large data
}

通过这种方式,您只需要拥有CommentAttachment Id即可加载FileContent,并且您可以随时包含它。

答案 1 :(得分:0)

返回null getter,但允许setter在EF 6.0和OData v4中运行。

我遇到过同样的问题。接受的答案肯定是一个可行的选择,我今天几乎实现了它,但我希望在代码中执行任务。我的模型与您可用的byte[] Timestamp列的可用内容略有不同。如果它可以在以后协助某人,则发布此解决方法。

对于我的情况,byte[] FileContents用作目录存储库的备份,如果由于各种原因导致前端被清除,我们使用数据库来重建目录结构和文件内容。基本上我们只有POST / SET FileContents,我们从未通过前端程序读取它。

public partial class CommentAttachment
{
     //required for overriding get/set auto-property
     private byte[] _FileContents; 

     public int FileId { get; set; }
     public int CommentID { get; set; }
     public string FileName { get; set; }
     public int FileSize { get; set; }
     public byte[] FileContents 
     { 
          get
          {
               return Timestamp != null ? null : _FileContents;
          } 
          set
          {
               _FileContents = value;
          }
     }  // holds large data

     public virtual TicketComment TicketComment { get; set; }
     //Concurrency Token - triggered on create or update
     public byte[] Timestamp { get; set; }
 }

以上允许我们的数据库表保持不变,只有EF POCO发生了变化。创建CommentAttachment记录时,Timestamp字段为空/不存在,因为它是由数据库触发的;这允许填充_FileContents。选择记录时,Timestamp会填充数据库中的值,因此FileContents设置为null,以避免查询大型数据集。

PUT / PATCH / POST在应用于OData v4时也能正常使用此方法,因为Timestamp没有为插入/更新传递,因为它是数据库触发的填充。