实体框架 LINQ 投影到自定义类型中导致数据丢失

3

我有一个承包商和安全委员会之间的多对多关系。它们由一个桥接表ContractorsSafetyCouncils连接,该表由ContractorId和SafetyCouncilId组成。这两列形成一个复合键。在EF4中,这种关系被正确地映射。承包商实体具有属性:

public virtual ICollection<SafetyCouncil> SafetyCouncils
{
    get;
    set;
}

安全委员会实体具有以下属性:
public virtual ICollection<Contractor> Contractors
{
    get;
    set;
}

当从单个承包商或安全委员会实体中通过延迟加载访问这些属性时,它们的工作方式与预期完全相同。但是,在查询中访问此关系时:
from c in ContractorRepository.All()
where c.PQFs.Count() > 0
let psmAudits = c.PQFs.SelectMany(pqf => pqf.Audits)
let psmAudit = psmAudits.FirstOrDefault(audit => audit.CompletedDate == psmAudits.Max(a => a.CompletedDate))
let scsAudits = c.PQFs.SelectMany(pqf => pqf.SCSAudits)
let scsAudit = scsAudits.FirstOrDefault(audit => audit.CompletedDate == scsAudits.Max(a => a.CompletedDate))
select new MasterListItem()
{
    AdministratorNotes = c.AdminFlags.Where(f => f.IsActive && f.ForPQF).Select(f => f.Text),
    CanViewInfo = false,
    ContractorName = c.ContractorName,
    ContractorId = c.Id,
    ContractorTaxId = c.TaxId,
    SafetyCouncilIds = c.SafetyCouncils.Select(sc => sc.Id),
    PQFSubmitted = c.PQFs.Max(p => p.PQFInfo.SubmittedDate.Value),
    PSMAuditId = psmAudit.Id,
    PSMAuditComplete = psmAudit.CompletedDate,
    PSMAuditStatus = psmAudit.Status.Description,
    SCSAuditId = scsAudit.Id,
    SCSAuditComplete = scsAudit.CompletedDate
};

问题出现在:


SafetyCouncilIds = c.SafetyCouncils.Select(sc => sc.Id),

对于每个记录,SafetyCouncilIds集合都没有成员,而根据数据库中的数据,每个记录应该至少有一个与之关联的SafetyCouncilId。
如果我运行相同的查询,但是将其投影到匿名类型而不是MasterListItem类型中,则可以正常工作。为什么不能将此查询投影到我的自定义类型中?
更新:我的MasterListItem POCO包含以下属性:
public string SafetyCouncilIdsString
{
    get;
    set;
}

public IEnumerable<int> SafetyCouncilIds
{
    set
    {
        StringBuilder sb = new StringBuilder(",");

        foreach (var id in value)
        {
            sb.Append(id);
            sb.Append(",");
        }

        this.SafetyCouncilIdsString = sb.ToString();
    }
}

问题的原因是 SafetyCouncilIds 属性。我将其更改为自动属性,然后在其他地方构建字符串并投影到 POCO 上,效果非常好。


1
我还尝试在 LinqPad 中运行与上面查询等效的语句,结果返回了预期的结果。 - Bobby Richard
3
LINQPad会以与您的代码相同的方式运行您的查询,因此如果在LINQPad中可以正常工作,那么问题可能出在您的代码而不是映射上。您这里的查询看起来没问题,除了当您想要使用“Any”时就不应该使用“Count”。 - Craig Stuntz
我已经确定,将投影到自定义类型MasterListItem中会导致问题。如果我投影到匿名类型中,则SafetyCouncilIds集合将被正确填充。我可以解决这个问题,但理想情况下我想投影到自定义类型中。 - Bobby Richard
1
将投影到POCO上的操作与投影到匿名类型上的操作完全相同,因此我猜测该类型存在一些异常。不过,由于您没有展示其定义,所以这只是一个猜测。 - Craig Stuntz
Craig,我正在复制和粘贴我的POCO代码,并找到了解决方案。感谢您指导我正确的方向,也感谢您提供有关Any()与Count()的提示。 - Bobby Richard
3个回答

2
public IEnumerable<int> SafetyCouncilIds
{
    set
    {
        StringBuilder sb = new StringBuilder(",");

        foreach (var id in value)
        {
            sb = sb.Append(id).Append(","); // <-- try this
            // *or sb = sb.AppendFormat("{0},", id);*
        }

        this.SafetyCouncilIdsString = sb.ToString();
    }

}


0

SafetyCouncilIds属性是问题的原因。我将其更改为自动属性,并在其他地方构建了字符串,然后投影到POCO上就像魔法一样起作用。


0

我有两个建议:

  1. 尝试通过删除查询中的任何额外部分来隔离问题。
  2. 比较生成的两个 SQL 查询并找到不同之处。

很遗憾,如果没有访问您的代码或模式,我无法提供更好的答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接