2015-12-20 18 views
5

ich das folgende Szenario habe:EF6 eindeutige Einschränkung auf Fremdschlüssel

public class Book { 
     [Key] 
     public string Isbn { get; set; } 
     public string Title { get; set; } 
     public int Stock { get; set; } 
     public Author Author { get; set; } 
} 

public class Author { 
    public int AuthorId { get; set; } 
    [Index(IsUnique = true)] 
    [StringLength(50)] 
    public string Name { get; set; } 

    public ICollection<Book> Books { get; set; } 
} 

Ich suche Bücher, und die damit verbundene Autoren einfügen, wenn nötig. Ich habe folgenden naiven Code, der (ziemlich viel erwartet) bricht:

var author = _ctx.Authors.FirstOrDefault(x => x.Name == command.Author); 

if (author == null) 
    author = new Author { Name = command.Author }; 

var book = new Book 
{ 
    Isbn = command.Id, 
    Title = command.Title, 
    Stock = command.Count, 
    Author = author 
}; 

_ctx.Books.Add(book); 

await _ctx.SaveChangesAsync(); 

Was ich sehe ist, dass manchmal die FirstOrDefault zurückkehrt null, aber der Einsatz versagt wegen Verletzung des eindeutigen Index für der Name des Autors Gibt es einige Tricks, die es ermöglichen, dies simpel zu machen? Ich denke, ich könnte ein gespeichertes Proc verwenden, möchte es aber möglichst auf der Client-Seite tun.

+1

Der einzige Grund, den ich sehen kann, dass dies brechen würde, wenn Sie mehrere Bücher gleichzeitig hinzufügen und der 'Autor' hinzugefügt wird durch einen anderen Prozess zwischen, wenn Sie es nachschlagen und wenn das Element zur Sammlung hinzugefügt wird. Der einfachste Weg, um diese Art von Nebenläufigkeit Problem zu behandeln, wäre meiner Meinung nach, die Ausnahme zu fangen, das Buch an den Autor, der jetzt in der DB ist, anhängen und dann erneut einreichen. – Claies

+0

1. hast du es versucht? Autor.Books.Add (Buch); ctx.SaveChangesAsync(); 2. Zum Buch hinzufügen: public int AuthorId {get; einstellen; } öffentlicher virtueller Autor Autor {erhalten; einstellen; } – W92

+0

Claies Beobachtung ist richtig ... das Rennen ist genau das Problem, und ich versuche, einen Workaround zu finden. @ W92, ja ... habe das probiert. Es entsteht der gleiche Race-Zustand. Das Problem ist auf dem Autor einfügen. – ashic

Antwort

3

Nach verschiedenen Dinge zu versuchen, habe ich mit folgendem gegangen:

var author = _ctx.Authors.SqlQuery(
    "with data as (select @author as [name]) " + 
    "merge Authors a " + 
    "using data s on s.[name] = a.[name] " + 
    "when not matched by target " + 
    "then insert([name]) values(s.[name]); select * from Authors where [name][email protected]", new SqlParameter("author", command.Author)).Single(); 


var book = new Book 
{ 
    Isbn = command.Id, 
    Title = command.Title, 
    Stock = command.Count, 
    Author = author 
}; 

_ctx.Books.Add(book); 

await _ctx.SaveChangesAsync(); 

Während nicht schön, das die Racebedingung zwischen dem Autor Prüfung und Einfügen mit db nativen Funktionen nicht verhindert. ORMs und undichte Abstraktionen, eh :)

Ich denke, ich könnte den Bucheinschub auch dort hineinlegen, oder das Ganze zu einem Sproc machen. Wenn jemand mit einem ORM nativen Ansatz kommt, der auf dieses Szenario reagiert, bin ich ganz Ohr :)

Verwandte Themen