EF5认为我的外键是空的......当它不是时

时间:2013-09-13 17:22:18

标签: c# foreign-keys entity-framework-5

我有一个现有的数据库,我首先使用代码。我对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不能为null的异常。当我查看数据库时,该列可以为空,但其中没有空值。奇怪的。这是一个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和CompanyEntity。

在ComputerEntity内部我改变了:

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

为:

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

现在,当我测试时,我得到一个例外:
导航属性&#39; ClientID&#39;不是类型&#39; ComputerEntity&#39;的声明属性。验证它是否未从模型中明确排除,并且它是有效的导航属性。

堆栈跟踪:    在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.DbModelBuilder.Build(DbConnection providerConnection)    在System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)    在System.Data.Entity.Internal.RetryLazy 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.InternalSet 1.Initialize()    在System.Data.Entity.Internal.Linq.InternalSet 1.get_InternalContext() at System.Data.Entity.Infrastructure.DbQuery 1.System.Linq.IQueryable.get_Provider()    在System.Linq.Queryable.FirstOrDefault [TSource](IQueryable 1 source, Expression 1谓词)    在C:\ Projects \ Reporting \ Data \ Reporting.Data \ InventoryRepository.cs中的Reporting.Data.InventoryRepository.FindComputerByHostname(String hostname,String client):第22行    在C:\ Projects \ Reporting \ Business \ Reporting.Services \ InventoryService.cs中的Reporting.Services.InventoryService.GetComputerDetails(String hostname,String client):第29行    在C:\ Projects \ Reporting \ Tests \ Reporting.Services.Tests \ InventoryTests.cs中的Reporting.Services.Tests.InventoryTests.GetComputerDetailsTest()中:第39行

1 个答案:

答案 0 :(得分:0)

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

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