Entity Framework核心无钥匙导航问题

Entity Framework Core Keyless Navigation Problem

我正在为我的公司构建概念验证。我们有一个现有的平台,我们将用现代技术逐步取代它。目前,我只能使用我们现有的具有多个无键表的数据库。我正在构建一个 Blazor WebAssembly 应用程序,它使用 gRPC 调用 .net 核心 Web 应用程序。我的问题是我正在使用 EF Core 与现有数据库通信,但在调用 DbContext.Attach(shipment)

时出现异常
"The navigation '' cannot be added because it targets the keyless entity type 'Document'. Navigations can only target entity types with keys."

DocumentAttach 实体上的导航 属性 到 DbContext

Shipment 是一个非常庞大且复杂的数据结构,深入了很多层。有没有办法避免在模型结构中为每个实体 DbContext.Entry(entity).State = EntityState.Added 设置实体状态?

或者可能将 DbSet 的 CRUD 操作映射到存储过程?

编辑

这是模式的一个大大缩短的版本,但这就是与问题相关的全部内容。

public class Shipment
{
    public int Id { get; set; }
    // 60 other properties

    public virtual ICollection<Document> Documents { get; set; }
}

public class Document
{
    public int ShippingId { get; set; }
    public string DocumentType { get; set; }
    public byte[] Content { get; set; }

    public virtual Shipment Shipment { get; set; }
}

当我尝试将 Shipment 实体附加到 DbContext 或手动设置其状态时,出现上述异常。

同样,我现在无法更改数据库架构,还有许多其他模型类似于 Document,它们没有密钥或添加密钥的方法。

编辑 2

我知道这需要进一步解释。显然,DbContext 将无法 Insert/Update/Delete,因为没有密钥,它就不知道如何操作。我所需要的只是在获取 Shipping 实体并设置导航 属性 Documents 时能够读取。但是在保存Shipping时,完全忽略导航属性。

如果该文档 class 反映了文档 table 的完整架构,那么您不能也不应该尝试通过 EF 导航属性关联文档。虽然架构可以完美地与来自没有 PK 的 table 的单向关系一起运行,但 EF 无法以这种方式管理关系。您期望如何将一份文件与另一份文件区分开来?系统可能永远不需要,但作为一个旨在可靠地加载和管理数据的 ORM,这是一个要求。

通常在 table 没有 PK 的情况下,如果有足够的字段来唯一区分记录,您可以通过定义键来满足 EF。例如 ShippingId + CreatedAt,如果需要,可能还有 CreatedBy。但是,对于您概述的模式,只有二进制内容不能作为密钥的一部分。

如果您不能调整模式以引入无意义的键(所有 table 都应该有一个 PK)那么我会说您唯一的选择是就 EF 而言删除关联并加载文档通过装运完全分开。对于很少使用的潜在大二进制数据,拥有导航属性可能具有潜在的危险,因为尝试 Include 它们或让它们的延迟加载代理意外地被序列化程序之类的东西触发可能会使系统瘫痪。

为了证明@jdweng 是错误的,并且当实体模型在数据库中没有支持字段时我已经多次看到异常,我偶然发现了这个解决方案。

我将 public Guid Id { get; set; } = Guid.NewGuid(); 添加到我所有的无密钥实体,然后使用 ModelBuilderentity.HasNoKey(); 替换为 entity.HasAlternateKey(x => x.Id);

HasAlternateKey 的摘要:如果在指定属性上尚不存在一个备用键,则在模型中为此实体类型创建一个备用键。这将强制属性为只读。

这正是我要找的。