5

non riesco a ottenere la mia testa intorno a questo, le discussioni in tutto SO stato in cui mi sto facendo tutte le cose giuste, ma chiaramente Devo essermi perso qualcosa ...EF 0..1 ai molti rapporto aggiorna

Dato questi due defs oggetto ...

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

    [ForeignKey("Block")] 
    public int? BlockingCodeId { get; set; } 

    public virtual BlockingCode Block { get; set; } 

    ... 

} 

public class BlockingCode 
{ 
    [Key] 
    public int Id { get; set; } 
    public virtual ICollection<Invoice> Invoices { get; set; } 
    ... 
} 

E poi contesto con la configurazione appropriata rapporto ...

public class FaureciaContext : EFDataContext 
{ 
    public virtual DbSet<Invoice> Invoices { get; set; } 
    public virtual DbSet<BlockingCode> BlockingCodes { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.Entity<Invoice>() 
      .HasOptional(e => e.Block) 
      .WithMany(e => e.Invoices); 
    } 
} 

Perché quando faccio questo ...

// assume this invoice has a BlockingCode relationship 
var invoice = db.Invoices.First(); 
invoice.BlockingCodeId = null; 
db.Savechanges(); 

faccio ad avere questa eccezione ...

Operazione non riuscita: Il rapporto non potrebbe essere cambiato perché una o più delle proprietà chiave esterna è non annullabile. Quando viene apportata una modifica a una relazione , la proprietà chiave esterna correlata è impostata su un valore nullo. Se la chiave esterna non supporta valori Null, deve essere definita una nuova relazione, la proprietà chiave esterna deve essere assegnata a un altro valore non nullo oppure l'oggetto non correlato deve essere eliminato.

EDIT:

ho pensato di aggiungere, come la risposta qui in realtà non sottolineare la vera risposta al problema che ho avuto ...

Si è scoperto che il riferimento in questione non era il problema ero in realtà l'aggiornamento un'altra proprietà bambino della classe di fattura più in alto il codice da qualcosa di simile ....

invoice.Lines = MergLines(newVersion, dbVersion); 

il mio codice fusione ha funzionato bene, ma come qualsiasi utente appassionato EF saprebbe y non puoi semplicemente "sostituire una collezione di bambini" in questo modo, devi rimuovere il vecchio e aggiungere il nuovo come appropriato.

+0

E se avete fatto 'modelBuilder.Entity () hasMany (e. => e.Invoices) .WithOptional (e => e.Block) .HasForeignKey (e => e.BlockingCodeId) '. Almeno è così che una relazione simile è impostata in una prima versione del DB che ho fatto. SideNote: Questo è il motivo per cui non faccio mai il codice prima. Preferisco impostare il DB e quindi lasciare che EF capisca questa cosa. – juharr

+0

no ... buona chiamata però: ( – War

+0

Sospetto che 'Invoice.BlockingCodeId' in DB sia un vincolo di chiave esterna con null. – shadow

risposta

1

Quindi, Reverse Engineering questo da quello che presumo sia la struttura della tabella di SQL di base si sta lavorando con ...

Block Tabella:

Block Table Definition

fattura Tabella:

Invoice Table Definition

E con una relazione di chiave esterna definita tra Invoice.BlockingCodeId e Bl ock.Id ...

FK Relationship

ottengo le seguenti classi di entità codice-primo e il contesto quando si lascia EF crearli dal DB fisico:

[Table("Block")] 
public partial class Block 
{ 
    public Block() 
    { 
     Invoices = new HashSet<Invoice>(); 
    } 

    public int Id { get; set; } 

    [Required] 
    [StringLength(50)] 
    public string Description { get; set; } 

    public virtual ICollection<Invoice> Invoices { get; set; } 
} 

[Table("Invoice")] 
public partial class Invoice 
{ 
    public int Id { get; set; } 

    public int? BlockingCodeId { get; set; } 

    [Required] 
    [StringLength(50)] 
    public string Description { get; set; } 

    public virtual Block Block { get; set; } 
} 

public partial class TestContext : DbContext 
{ 
    public TestContext() 
     : base("name=TestContext") 
    { 
    } 

    public virtual DbSet<Block> Blocks { get; set; } 
    public virtual DbSet<Invoice> Invoices { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<Block>() 
      .HasMany(e => e.Invoices) 
      .WithOptional(e => e.Block) 
      .HasForeignKey(e => e.BlockingCodeId); 
    } 
} 

Quando gli enti e il contesto sono configurati come sopra, il seguente codice esegue senza edizione e vedo quello che mi aspetterei nel database SQL:

var context = new TestContext(); 
var block = new Block { Description = "Block 1" }; 
var invoices = new List<Invoice> 
        { 
         new Invoice { Description = "Invoice 1" }, 
         new Invoice { Description = "Invoice 2" } 
        }; 

invoices.ForEach(i => block.Invoices.Add(i)); 
context.Blocks.Add(block); 
context.SaveChanges(); 

block = null; 
var invoice = context.Invoices.First(); 
invoice.Block = null; 
context.SaveChanges(); 

Dopo l'esecuzione, il risultante dat uno Stato è ...

Block Table: Tabella

Block Data

Fattura:

Invoice Data

+0

Grazie, è esattamente quello che mi aspetterei ... Penso che l'errore, essendo ciò che è, non è molto utile e la traccia dello stack semplicemente non mi dà abbastanza informazioni per determinare l'esatta riga di codice (probabilmente ho identificato la linea usurata) ... Penso che forse sto guardando la linea sbagliata di codice e questo lo conferma. Dubito molto che EF sia in errore. – War