web-dev-qa-db-ger.com

Beim Speichern von Entitäten, die keine Fremdschlüsseleigenschaften für ihre Beziehungen verfügbar machen, ist ein Fehler aufgetreten

Ich habe einen einfachen Code in Entity Framework 4.1 Code zuerst:

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();

Das Problem ist, dass ich einen Fehler erhalte

Beim Speichern von Entitäten, die keine Fremdschlüsseleigenschaften für ihre Beziehungen verfügbar machen, ist ein Fehler aufgetreten. Die EntityEntries-Eigenschaft gibt null zurück, da eine einzelne Entität nicht als Quelle der Ausnahme identifiziert werden kann. Die Behandlung von Ausnahmen beim Speichern kann vereinfacht werden, indem Fremdschlüsseleigenschaften in Ihren Entitätstypen verfügbar gemacht werden. Weitere Informationen finden Sie in der InnerException.

beim

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

Ich verstehe nicht, warum die ähnliche Operation funktioniert. Stimmt etwas mit meinem Modell oder mit ef-code-first nicht?

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

Für diejenigen von Ihnen, die diesen Fehler mit allen richtig definierten Schlüsseln immer noch haben würden, werfen Sie einen Blick auf Ihre Entitäten und stellen Sie sicher, dass Sie kein datetime-Feld mit einem Nullwert verlassen.

161
Baral

Diese Fehlermeldung kann aus irgendeinem Grund ausgegeben werden. Die Eigenschaft 'InnerException' (oder deren InnerException oder deren InnerException usw.) enthält die eigentliche Hauptursache des Problems.

Es wäre natürlich nützlich zu wissen, wo das Problem aufgetreten ist - welche Objekte in der Arbeitseinheit verursachen das Problem? Die Ausnahmemeldung zeigt normalerweise die Eigenschaft 'EntityEntries' an. In diesem Fall ist dies jedoch aus irgendeinem Grund nicht möglich. Diese Diagnosekomplikation, bei der die Eigenschaft "EntityEntries" leer ist, beruht anscheinend darauf, dass einige Entities "keine Fremdschlüsseleigenschaften für ihre Beziehungen verfügbar machen".

Selbst wenn das OP den Fehler erhält, weil DateTimes für die zweite Instanz von User nicht initialisiert werden konnte, wird die Diagnose kompliziert, da "EntityEntries" leer sind und eine verwirrende Meldung auf oberster Ebene angezeigt wird. .. weil eine ihrer Entitäten keine 'Fremdschlüsseleigenschaften verfügbar macht'. Um dies zu beheben, sollte Avatar ein public virtual ICollection<User> Users { get; set; } Eigenschaft definiert.

13
David Bullock

Das Problem wurde durch Hinzufügen einer FK-Eigenschaft behoben.

6
user278618

In meinem Fall gab mir die folgende Situation die gleiche Ausnahme:

Stellen Sie sich ein Code-First-EF-Modell vor, in dem Sie eine Garage -Entität haben, die eine Sammlung von Car -Entitäten enthält. Ich musste ein Auto aus der Garage entfernen, damit ich den folgenden Code erhielt:

garageEntity.Cars.Remove(carEntity);

Stattdessen hätte es so aussehen sollen:

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

Nur für andere, die ähnliche Probleme haben könnten. Ich hatte den gleichen Fehler, aber aus einem anderen Grund. In einem der untergeordneten Objekte definierte ich den [Schlüssel] als einen Wert, der für verschiedene Speichervorgänge gleich war. Ein blöder Fehler meinerseits, aber die Fehlermeldung führt Sie nicht sofort zum Problem.

2
Simon The Cat

In meinem Fall wurde die Ausnahme ausgelöst, weil EF eine Migration falsch erstellt hatte. Es fehlte das Setzen des Identität: true in der zweiten Tabelle. Gehen Sie also zu den Migrationen, bei denen die relevanten Tabellen erstellt wurden, und prüfen Sie, ob keine Identität hinzugefügt werden konnte.

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);

Eine ID-Spalte sollte eine Identität haben (d. H. Automatisch inkrementieren!), Daher muss dies ein EF-Fehler sein.

Sie können die Identität manuell mit SQL direkt zur Datenbank hinzufügen, ich bevorzuge jedoch die Verwendung von Entity Framework.

Wenn Sie auf dasselbe Problem stoßen, sehe ich zwei einfache Lösungen:

Alt 1

kehren Sie die fehlerhaft erstellte Migration mit um

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

Fügen Sie dann manuell identity: true zum Migrationscode hinzu und dann update-database erneut.

Alt 2

sie erstellen eine neue Migration, die Identität hinzufügt. Wenn Sie keine Änderungen an den Modellen haben und Sie ausführen

add-migration identity_fix

es wird eine leere Migration erstellt. Dann füge dies einfach hinzu

    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

Dieses Problem kann sich auch aus umgekehrten Schlüsseldeklarationen ergeben. Wenn Sie die Beziehung flüssig konfigurieren, stellen Sie sicher, dass die linken und rechten Tasten der richtigen Entität zugeordnet sind.

1
Edyn

Noch ein anderer Fall hier. Eine Abfrage wurde in eine Liste umgewandelt und dabei mit ihrem Konstruktor Entitäten für den Vergleich im linq-Ausdruck direkt nach der ToList () erstellt. Dadurch wurden Entitäten erstellt, die nach Beendigung des linq-Ausdrucks in den gelöschten Zustand versetzt wurden.
Jedoch! Es gab eine kleine Anpassung, durch die eine andere Entität im Konstruktor erstellt wurde, sodass diese neue Entität mit einer Entität verknüpft wurde, die als Gelöscht markiert war.

Code zur Veranschaulichung:

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();

Der Konstruktor von 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);
    }
}

Meine Lösung bestand darin, sicherzustellen, dass der gesamte Ausdruck in IQueryable erstellt wurde, damit keine Objekte erstellt werden.

0
Mixxiphoid

Ich hatte das gleiche problem In meinem Fall lag es an einem Datum/Uhrzeit-Feld mit einem Nullwert. Ich musste einen Wert an Datum und Uhrzeit übergeben, und alles lief gut

0
onlyme

Heute habe ich mich mit diesem Problem befasst und die oben genannten Lösungsmöglichkeiten ausprobiert, aber keine davon hat mir geholfen. Ich hatte UnitOfWork implementiert und das System hat die Daten zuletzt festgeschrieben, nachdem alle Datensätze hinzugefügt wurden.

In meinem Fall hat das System die beiden Modelle kombiniert und die Datenbank abgefragt

Ungültiger Objektname 'dbo.RoleModelUserModel'.

wo es sich eigentlich um zwei verschiedene Modelle handelte.

Ich habe dies behoben, indem ich die insert-Anweisungen neu angeordnet und zuerst die übergeordnete Entität hinzugefügt habe. In diesem Fall wurde der Benutzer zuerst hinzugefügt und das Problem behoben.

0
Nawaz Khan

Eine andere Antwort:

Ich habe das benutzt:

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

an Stelle von:

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

und habe die oben angegebene Fehlermeldung erhalten.

0
Greg Gum

Ich hatte den gleichen Fehler und in meinem Fall bestand das Problem darin, dass ich ein Beziehungsobjekt hinzufügte, das bereits "AsNoTracking" geladen hatte. Ich musste die Relationseigenschaft neu laden.

Übrigens, einige schlagen vor, "Attach" für Beziehungen zu verwenden, die bereits in db existieren. Ich habe diese Option jedoch nicht ausprobiert.

0
Hamed

Ich bin mir nicht ganz sicher, ob dies in Ihrem Fall hilfreich sein wird, da ich meine Tabellen mit der Fluent-API einrichte. Soweit ich das beurteilen kann, tritt das Problem jedoch unabhängig davon auf, ob das Schema mit Datenanmerkungen (Attributen) eingerichtet wurde. oder Fluent API (Konfiguration).

Es scheint einen Fehler in EF (v. 6.1.3) zu geben, da beim Aktualisieren der Datenbank auf die nächste Migration bestimmte Änderungen am Schema ausgelassen werden. Der schnellste Weg ist (während der Entwicklungsphase), alle Tabellen aus der Datenbank zu entfernen und Migrationen aus der Init-Phase erneut auszuführen.

Wenn Sie bereits in der Produktion sind, war die schnellste Lösung, die ich gefunden habe, das Schema in der Datenbank manuell zu ändern, oder, wenn Sie eine Versionskontrolle der Änderungen wünschen, die Methoden manuell zu manipulieren p () = und Down () in Ihrer Migration.

0

In meinem Fall bestand das Problem darin, dass ich eine Spalte falsch umbenannt habe, sodass bei der Migration zwei Spalten erstellt wurden, eine mit der Bezeichnung "TeamId" und eine mit der Bezeichnung "TeamID". C # kümmert sich, SQL nicht.

0
Duston