0

最初にコードを使用している既存のデータベースがあります。必要な場所に外部キーがあることを確認するために、SQL データベースのテーブルをクリーンアップしました。Entity_Company というテーブルを指す ClientID という null 許容の外部キーを持つ Inventory_Base というテーブルが 1 つあります。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 ;
    }

もう 1 つの奇妙さは、ComputerEntity で ClientID を int で null 可能にする必要があることです。そうしないと、ClientID を null にすることはできないという例外が発生します。データベースを見ると、列は null 可能ですが、null 値はありません。変。それがintであるという事実はありますか?何らかの形で関係を壊す?

アップデート
そこで、EF パワー ツールを使用してリバース エンジニアリングを行い、詳細を調べてみました。醜いテーブル名はすべてエンティティとして表示されましたが、これで問題ありません。CompanyEntity は Entity_Company になり、それを参照するすべてのものの ICollection があります。ComputerEntity は Inventory_Base になりましたが、ロードされないという同じ問題があります。謎に追加するために、CompanyEntity (現在は Entity_Company) の他のコレクションは期待どおりにナビゲートします! 自動生成されたマッピング ファイルを確認したところ、破損したコレクションにはすべて、すべてのプロパティに .IsRequired() が含まれています。通常動作するコレクションにはこれがありません。また、壊れたコレクションの ClientID はすべて int ですか? 通常の null 非許容の int ではありません。理由はわかりませんが、これは問題だと思います。企業とそれぞれのコンピューターの間で目前の問題に焦点を当てると、ComputerEntity (現在は Inventory_Base) には恐ろしい int? があります。自動生成されたマッピング ファイルで。SELECT * FROM Inventory_Base WHERE ClientID IS NULL を使用して SQL データベースをチェックしましたが、何も得られませんでした。テーブルを変更して ClientID 列を null 非許容にしようとしましたが、SQL は、テーブルを再作成できないため、変更できないと文句を言います。通常、これはそこにnull値があったことを期待します...しかし、ありません。問題なくうまく機能するエンティティ コレクションに対応する他のテーブルを変更できます。おそらく、問題は破損した 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 モデル) で System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Configure (EdmEntityType entityType、EdmModel モデル) で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.RetryLazy2.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 predicate) で 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 で複製したデータベースを指していました。テストデータベースにnullがないようにFKを更新したことはありません。app.config を本番 DB を指すように変更した後、もちろん、CompanyEntity と ComputerEntity の間の適切な関係が見つかりました。これは、ClientID が null ではなくなり、データが正しくフェッチされるためです。

外部キー ClientID を int に設定するとどうなりますか? それは今でも魔法のように機能します。これは、null 可能であると言っても、null キーがなくなったためだと思います。ComputerEntity が存在するテーブルに null 値を再導入する予定はありませんが、このプロジェクトを進めていくと、そのような状況がさらに増えると確信しています。Null 許容外部キーが自動 EF マッピングでどのように機能するかについて、誰かが確かな答えをくれる場合は、代わりにその答えを喜んで受け入れます。私は FluentAPI に近づかず、まっすぐなデータ注釈を行おうとしています。おそらく答えは、胸やけの原因となっている慣習を取り除くことです。

于 2013-09-16T15:26:42.860 に答える