EF6对外键的唯一约束

ash*_*hic 5 c# entity-framework-6

我有以下场景:

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; }
}
Run Code Online (Sandbox Code Playgroud)

我希望在需要时插入书籍和相关作者.我有以下天真的代码,它打破了(非常期待):

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();
Run Code Online (Sandbox Code Playgroud)

我所看到的是,有时,FirstOrDefault返回null,但由于违反了作者名称上的唯一索引,插入失败.是否有一些EF技巧可以让它以简单的方式发生?我想我可以使用存储过程,但如果可能的话,我想做客户端.

ash*_*hic 3

在尝试了各种事情之后,我采用了以下方法:

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]=@author", 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();
Run Code Online (Sandbox Code Playgroud)

虽然不太漂亮,但这确实防止了作者检查和使用数据库本机功能插入之间的竞争条件。ORM 和漏洞抽象,嗯:)

我想我也可以把书的插页放在那里,或者把整个东西变成一个存储过程。如果有人想出适合这种场景的 ORM 原生方法,我会洗耳恭听:)