0

我有一个现有的数据库,我首先使用代码。我对我的 SQL 数据库中的表进行了一些清理,以确保在需要的地方有外键。我有一个名为 Inventory_Base 的表,它有一个名为 ClientID 的可空外键,它指向名为 Entity_Company 的表。Inventory_Base 映射到我的名为 ComputerEntity 的实体对象,Entity_Company 映射到我的名为 CompanyEntity 的实体对象。我相信我的导航道具设置正确,但如果我搞砸了,请告诉我。我遇到的问题是从未加载 CompanyEntity 导航属性。我尝试删除两者的导航属性,以便可以查看 ComputerEntity 对象中 ClientID 的值,但即使该列存在于数据库中,它也永远不会加载!我怀疑 EF 约定看到了“ID”这个词

我的 ComputerEntity 是这样定义的,我真的很想加载 CompanyEntity:

[Table("Inventory_Base")]
public class ComputerEntity
{
    // primary key
    [Key]
    public int AssetID { get; set; }

    // foreign keys
    [ForeignKey("CompanyEntity")]
    public int? ClientID { get; set; }

    // navigation props
    [ForeignKey("ClientID")]
    public virtual CompanyEntity CompanyEntity { get; set; }

    // these props are fine without custom mapping
    public string Hostname { get; set; }
    public string ServiceTag { get; set; }
}

这是我传说中的 CompanyEntity 永远不会加载:

[Table("Entity_Company")]
public class CompanyEntity
{
    protected CompanyEntity() {}

    // primary key
    [Key]
    public int ClientID { get; set; }

    // foreign key

    // nav props
    public virtual ICollection<ComputerEntity> ComputerEntities { get; set; }

    // regular props

    // custom mappings
    [Column("CompanyName", TypeName = "nvarchar(MAX)")]
    public string Name { get; set; }

    [Column("FQDN", TypeName = "nvarchar(MAX)")]
    public string Domain { get; set; }
}

我正在尝试查找其主机名属性与输入匹配的计算机,并且该计算机属于特定公司。我有一个我正在查询的 DbSet,并假设由于存在导航属性,它可以访问关联的 CompanyEntity 对象的属性。到目前为止,我认为是错误的,并且我一生都看不到导致问题的原因。这是我尝试获取计算机的方式:

    public ComputerEntity FindComputerByHostname(string hostname, string client)
    {
        var computer = DbSet.Where(x => x.Hostname == hostname && x.CompanyEntity.Name == client).FirstOrDefault(); // <-- always null!
        var test = DbSet.Where(x.CompanyEntity.Name == client).ToList() // <-- never finds anything, which is why I suspect a non-working relationship
        return computer ;
    }

另一个奇怪的是,在我的 ComputerEntity 中,我必须使用 int 使 ClientID 为空?否则我会得到一个异常,即 ClientID 不能为空。当我查看数据库时,该列可以为空,但其中没有空值。诡异的。这是一个int的事实吗?以某种方式破坏关系?

更新
因此,我使用 EF 电动工具进行逆向工程,以尝试获取更多细节。它给了我所有丑陋的表名作为实体,这很好。CompanyEntity 现在是 Entity_Company,它拥有所有引用它的 ICollection。ComputerEntity 现在是 Inventory_Base,我遇到了同样的问题,它从未加载过。为了增加谜语,CompanyEntity(现在的 Entity_Company)的其他集合确实按预期导航!我检查了自动生成的映射文件,并且破坏的集合都有每个属性的 .IsRequired() 。正常工作的集合没有这个。此外,被破坏的集合都有它们的 ClientID 是 int 吗?而不是常规的不可为空的 int。虽然我不知道为什么,但我认为这是一个问题。ComputerEntity(现在的 Inventory_Base)专注于公司及其各自计算机之间手头的问题,具有可怕的 int? 在自动生成的映射文件中。我用 SELECT * FROM Inventory_Base WHERE ClientID IS NULL 检查了 SQL 数据库,但我什么也没得到。我尝试修改表以使 ClientID 列不可为空,并且 SQL 抱怨它不能这样做,因为无法重新创建表。通常我希望这是那里有一个空值......但没有。我可以修改与实体集合相对应的其他表,这些表已经很好地播放而没有问题。也许问题是损坏的 SQL 表?我不认为这是可能的,但如果有人知道一个 DBCC 命令来检查,那就太好了。为了使我的解决方案与这个问题保持一致,

在 ComputerEntity 内部我改变了:

[ForeignKey("CompanyEntity")]
public int? ClientID {get;set;}

至:

[ForeignKey("CompanyEntity")]
public int ClientID {get;set;}

现在,当我测试时,我得到了一个例外:
导航属性“ClientID”不是“ComputerEntity”类型的声明属性。验证它没有被明确地从模型中排除,并且它是一个有效的导航属性。

堆栈跟踪:在 System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.ConfigureAssociations(EdmEntityType entityType, EdmModel model) 在 System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Configure(EdmEntityType entityType, EdmModel model) 在System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.ConfigureEntities(EdmModel 模型) 在 System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.Configure(EdmModel 模型) 在 System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo) 在 System.Data.Entity.Internal.RetryLazy 的 System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext) 的 System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)2.GetValue(TInput input) at System.Data.Entity.Internal.LazyInternalContext.InitializeContext() at System.Data.Entity.Internal.InternalContext.Initialize() at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) at System.Data.Entity.Internal.Linq.InternalSet1.Initialize() 在 System.Data.Entity.Internal.Linq.InternalSet 1.get_InternalContext() at System.Data.Entity.Infrastructure.DbQuery1.System.Linq.IQueryable.get_Provider() 在 System.Linq.Queryable.FirstOrDefault[TSource](IQueryable 1 source, Expression1 谓词) 在 Reporting.Data.InventoryRepository .FindComputerByHostname(String hostname, String client) in c:\Projects\Reporting\Data\Reporting.Data\InventoryRepository.cs:line 22 at Reporting.Services.InventoryService.GetComputerDetails(String hostname, String client) in c:\Projects\ Reporting\Business\Reporting.Services\InventoryService.cs:c:\Projects\Reporting\Tests\Reporting.Services.Tests\InventoryTests.cs 中 Reporting.Services.Tests.InventoryTests.GetComputerDetailsTest() 的第 29 行:第 39 行

4

1 回答 1

0

废话,这个问题的答案很愚蠢。对于我的单元测试,在我的 app.config 中,我指向了我的克隆数据库。我从未将 FK 更新为在测试数据库中没有空值。在将我的 app.config 更改为指向我的生产数据库之后,它当然找到了 CompanyEntity 和 ComputerEntity 之间的正确关系,因为 ClientID 不再为空并且它可以正确获取数据。

如果我将外键 ClientID 设置为 int?它现在也神奇地起作用了。我怀疑这是因为没有更多的空键,即使我说它可以为空。我不打算将空值重新引入 ComputerEntity 所在的表中,但是当我完成这个项目时,我很确定我会发现更多的情况。如果有人能给我一个关于可空外键如何与自动 EF 映射一起工作的可靠答案,我会很乐意接受这个答案。我试图远离 FluentAPI 并直接进行数据注释。也许答案是删除任何导致我胃灼热的惯例。

于 2013-09-16T15:26:42.860 回答