web-dev-qa-db-ja.com

関係の外部キープロパティを公開しないエンティティの保存中にエラーが発生しました

最初にEntity Framework 4.1コードで簡単にコードを作成します:

PasmISOContext db = new PasmISOContext();
var user = new User();
user.CreationDate = DateTime.Now;
user.LastActivityDate = DateTime.Now;
user.LastLoginDate = DateTime.Now;
db.Users.Add(user);

db.SaveChanges();
user.Avatar = new Avatar() { Link = new Uri("http://myUrl/%2E%2E/%2E%2E") };
db.SaveChanges();


db.Users.Add(new User() { Avatar = new Avatar() { Link = new Uri("http://myUrl/%2E%2E/%2E%2E") } });
db.SaveChanges();

問題は、エラーが発生することです

関係の外部キープロパティを公開しないエンティティの保存中にエラーが発生しました。単一のエンティティを例外のソースとして識別できないため、EntityEntriesプロパティはnullを返します。保存中の例外の処理は、エンティティタイプの外部キープロパティを公開することで簡単にできます。詳細については、InnerExceptionを参照してください。

db.Users.Add(new User() { Avatar = new Avatar() { Link = new Uri("http://myUrl/%2E%2E/%2E%2E") } });
db.SaveChanges();

同様の操作が機能する理由がわかりません。私のモデル、またはef-code-firstに何か問題がありますか?

public class Avatar
{
    [Key]
    public int Id { get; set; }

    [Required]
    public string LinkInString { get; set; }

    [NotMapped]
    public Uri Link
    {
        get { return new Uri(LinkInString); }
        set { LinkInString = value.AbsoluteUri; }
    }
}

public class User
{
    [Key]
    public int Id { get; set; }
    public string UserName { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
    public Avatar Avatar { get; set; }
    public virtual ICollection<Question> Questions { get; set; }
    public virtual ICollection<Achievement> Achievements { get; set; }

    public DateTime CreationDate { get; set; }
    public DateTime LastLoginDate { get; set; }
    public DateTime LastActivityDate { get; set; }
}
48
user278618

すべてのキーが適切に定義された状態でこのエラーが引き続き発生する場合は、エンティティを確認し、datetimeフィールドにnull値を残さないようにしてください。

161
Baral

このエラーメッセージは、何らかの理由でスローされる可能性があります。 「InnerException」プロパティ(またはそのInnerException、またはそのInnerExceptionなど)には、問題の実際の主な原因が含まれています。

もちろん、問題が発生した場所-作業ユニット内のどのオブジェクトが問題を引き起こしているのかを知ることは有用でしょうか?例外メッセージは通常、 'EntityEntries'プロパティで通知しますが、この場合、何らかの理由で実行できません。 「EntityEntries」プロパティが空であるというこの診断の複雑さは、一部のエンティティが「関係の外部キープロパティを公開しない」ためです。

DateTimeの2番目のインスタンスのUsersの初期化に失敗したためにOPがエラーを受け取った場合でも、診断の複雑さ-'EntityEntries'が空であり、トップレベルのメッセージが混乱します。 ..エンティティの1つが「外部キープロパティを公開しない」ためです。これを修正するには、Avatarpublic virtual ICollection<User> Users { get; set; }プロパティを定義する必要があります。

13
David Bullock

この問題は、FKプロパティを追加することで解決しました。

6
user278618

私の場合、次の状況で同じ例外が発生しました。

Garageエンティティのコレクションを持つCarエンティティがあるコードファーストEFモデルを想像してください。ガレージから車を取り外す必要があったので、次のようなコードになりました。

garageEntity.Cars.Remove(carEntity);

代わりに、次のように見えるはずです。

context.Cars.Remove(carEntity);
3
Memet Olsen

同様の問題を抱えているかもしれない他の人のために。同じエラーが発生しましたが、理由は異なります。子オブジェクトの1つで、[キー]を異なる保存で同じ値として定義しました。私の側の愚かな間違いですが、エラーメッセージがすぐに問題につながるわけではありません。

2
Simon The Cat

私の場合、EFが移行を誤って作成したため、例外がスローされました。 2番目のテーブルでidentity:trueを設定できませんでした。したがって、関連するテーブルを作成した移行に進み、IDの追加に失敗したかどうかを確認します。

CreateTable(
    "dbo.LogEmailAddressStats",
    c => new
        {
            Id = c.Int(nullable: false, identity: true),
            EmailAddress = c.String(),
        })
    .PrimaryKey(t => t.Id);

CreateTable(
    "dbo.LogEmailAddressStatsFails",
    c => new
        {
            Id = c.Int(nullable: false), // EF missed to set identity: true!!
            Timestamp = c.DateTime(nullable: false),
        })
    .PrimaryKey(t => t.Id)
    .ForeignKey("dbo.LogEmailAddressStats", t => t.Id)
    .Index(t => t.Id);

Id列にはID(つまり、自動インクリメント!)が必要なので、これはEFバグでなければなりません。

SQLを使用してIDをデータベースに直接手動で追加できますが、Entity Frameworkを使用することをお勧めします。

同じ問題に遭遇した場合、2つの簡単な解決策が表示されます。

Alt 1

誤って作成された移行を逆に

update-database -target:{insert the name of the previous migration}

次に、identity:trueを手動で移行コードに追加してから、update-databaseもう一度。

Alt 2

iDを追加する新しい移行を作成します。モデルに変更がなく、実行する場合

add-migration identity_fix

空の移行が作成されます。次に、これを追加するだけです

    public partial class identity_fix : DbMigration
    {
        public override void Up()
        {
            AlterColumn("dbo.LogEmailAddressStatsFails", "Id", c => c.Int(nullable: false, identity: true));
        }

        public override void Down()
        {
            AlterColumn("dbo.LogEmailAddressStatsFails", "Id", c => c.Int(nullable: false));
        }
    }
2
fredrik.hjarner

この問題は、逆キー宣言からも発生する可能性があります。 fluentを使用して関係を構成している場合は、左右のキーが正しいエンティティにマップされていることを確認してください。

1
Edyn

ここでさらに別のケース。クエリがリストにキャストされ、その間に、ToList()の直後のlinq式で比較するために、コンストラクターによってエンティティが作成されました。これにより、linq式の終了後に削除状態になったエンティティが作成されました。
しかしながら!コンストラクターに別のエンティティを作成する小さな調整があったため、この新しいエンティティは、削除済みとしてマークされたエンティティにリンクされました。

説明するコード:

query.Except(_context.MyEntitySetSet()
                .Include(b => b.SomeEntity)
                .Where(p => Condition)
                .ToList() // This right here calls the constructor for the remaining entities after the where
                .Where(p => p.Collection.First(b => Condition).Value == 0)
                .ToList();

MyEntityのコンストラクター:

public partial class MyEntity
{
    protected MyEntity()
    {
        // This makes the entities connected though, this instance of MyEntity will be deleted afterwards, the instance of MyEntityResult will not.
        MyEntityResult = new MyEntityResult(this);
    }
}

私の解決策は、オブジェクト全体が作成されないように、式全体がIQueryable内で行われるようにすることでした。

0
Mixxiphoid

同じ問題がありました。私の場合、これはnull値を持つdatetimeフィールドが原因でした。 datetimeに値を渡す必要があり、すべてがうまくいきました

0
onlyme

今日、私はこの問題に直面し、上記の可能な解決策を試しましたが、どれも私を助けませんでした。 UnitOfWorkパターンを実装し、すべてのレコードを追加した後、システムが最後にデータをコミットしました。

私の場合、システムは2つのモデルを組み合わせてDBを照会していました

無効なオブジェクト名「dbo.RoleModelUserModel」。

これらは実際には2つの異なるモデルでした。

Insert文の順序を変更し、最初に親エンティティを追加することでこれを修正しました。この場合、最初にユーザーを追加し、問題を解決しました。

0
Nawaz Khan

別の答え:

私はこれを使用しました:

public List<EdiSegment> EdiSegments { get; set; }

これの代わりに:

public virtual ICollection<EdiSegment> EdiSegments { get; set; }

上記のエラーメッセージが表示されます。

0
Greg Gum

同じエラーが発生しました。私の場合、問題は既に「AsNoTracking」がロードされていた関係オブジェクトを追加したことです。関係プロパティをリロードする必要がありました。

ところで、データベースに既に存在するリレーションに「アタッチ」を使用することを提案する人もいますが、私はそのオプションを試していません。

0
Hamed

Fluent APIを使用してテーブルを設定しているため、それがあなたのケースに役立つかどうか完全にはわかりませんが、私が知る限り、データ注釈(属性)を使用してスキーマが設定されているかどうかに関係なく問題が発生しますまたはFluent API(構成)。

EF(v。6.1.3)には、DBを次の移行に更新するときにスキーマへの特定の変更が省略されるため、バグがあるようです。これを回避する最も速いルートは(開発段階で)DBからすべてのテーブルを削除し、init段階から再度移行することです。

既に本番環境にいる場合、私が見つけた最も迅速な解決策は、DB内のスキーマを手動で変更するか、変更のバージョン管理が必要な場合は、メソッドを手動で操作することですp() =およびDown()移行中。

0

私の場合、問題は列の名前を不適切に変更したことでした。そのため、移行によって2つの列が作成されました。1つは「TeamId」、もう1つは「TeamID」です。 C#は気にしますが、SQLは気にしません。

0
Duston