如何添加条件以使用实体框架链接到实体来更新条目

本文关键字:实体 链接 框架 更新 何添加 添加 条件 | 更新日期: 2023-09-27 18:13:10

假设我有以下实体:

public class Library
{
    public int ID { get; set; }
    public ICollection<Book> Books { get; set; }
    public Library()
    {
        Books = new HashSet<Book>();
    }
}
public class Book
{
    public int ID { get; set; }
    public int LibraryID { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public DateTime PublicationDate { get; set; }
    public bool CheckedOut { get; set; }
}

有很多图书馆,每个图书馆都有很多书。图书馆中ID=1的人借出了ID=42的书,所以我想将CheckedOut属性更新为true。假设出于某种原因,我已经知道图书馆ID和图书ID,但不知道其他信息。我可以很容易地更新CheckedOut属性,而无需从数据库中获取所有图书数据:

Book book=new Book(){
    ID=42,
    LibraryID=1,
    CheckedOut=true
}
context.Books.Attach(book);
var entry=context.Entry(book);
entry.Property(b=>b.CheckedOut).IsModified=true;
context.SaveChanges();

这是我的问题。如果数据库中的LibraryID不是这本书的1,我怎么能强迫它失败?在普通SQL中,我可以写

UPDATE Books SET CheckedOut=1 WHERE ID=42 AND LibraryID=1

我如何用实体框架做同样的事情?

这里一个明显的用例是增加更多的安全性——例如,如果用户没有权限从除1以外的任何图书馆借阅一本书。

如何添加条件以使用实体框架链接到实体来更新条目

当您使用.Attach(book)时,您实际上是在告诉EF:嘿,这些是数据库中现有记录的原始值。所以在你的例子中EF会认为现有的book.LibraryID1。您可以利用这一事实,并通过配置LibraryID属性来强制EF执行所需的检查,该属性将被数据注释用作乐观并发令牌:

public class Book
{
    // ...
    [ConcurrencyCheck]
    public int LibraryID { get; set; }
}

或Fluent API:

modelBuilder.Entity<Book>()
    .Property(e => e.LibraryID).IsConcurrencyToken();

现在,如果您打开EF登录并执行您的代码片段,您将看到如下内容:

在14/10/2016 21:35:32 +03:00打开连接

UPDATE [dbo].[Books]
SET [CheckedOut] = @0
WHERE (([ID] = @1) AND ([LibraryID] = @2))
-- @0: 'True' (Type = Boolean)
-- @1: '42' (Type = Int32)
-- @2: '1' (Type = Int32)

和你要找的东西差不多

这种方法的唯一潜在问题是,当数据库中的LibraryID不是1时,您将得到DbUpdateConcurrencyException