使用存根實體

假設我們在多對多關係中有 Products 和 Categorys:

public class Product
{
    public Product()
    {
        Categories = new HashSet<Category>();
    }
    public int ProductId { get; set; }
    public string ProductName { get; set; }
    public virtual ICollection<Category> Categories { get; private set; }
}

public class Category
{
    public Category()
    {
        Products = new HashSet<Product>();
    }
    public int CategoryId { get; set; }
    public string CategoryName { get; set; }
    public virtual ICollection<Product> Products { get; set; }
}

如果我們想要將 Category 新增到 Product,我們必須載入產品並將類別新增到其 Categories,例如:

不好的例子:

var product = db.Products.Find(1);
var category = db.Categories.Find(2);
product.Categories.Add(category);
db.SaveChanges();

(其中 dbDbContext 的子類)。

這會在 ProductCategory 之間的聯結表中建立一條記錄。但是,此表僅包含兩個 Id 值。載入兩個完整實體以建立一個小記錄是浪費資源。

更有效的方法是使用在記憶體中建立的存根實體,即實體物件,僅包含最少的資料,通常只包含 Id 值。這就是它的樣子:

好例子:

// Create two stub entities
var product = new Product { ProductId = 1 };
var category = new Category { CategoryId = 2 };

// Attach the stub entities to the context
db.Entry(product).State = System.Data.Entity.EntityState.Unchanged;
db.Entry(category).State = System.Data.Entity.EntityState.Unchanged;

product.Categories.Add(category);
db.SaveChanges();

最終結果是相同的,但它避免了兩次到資料庫的往返。

防止重複

你要檢查關聯是否已存在,便宜的查詢就足夠了。例如:

var exists = db.Categories.Any(c => c.Id == 1 && c.Products.Any(p => p.Id == 14));

同樣,這不會將完整實體載入到記憶體中。它有效地查詢聯結表,只返回一個布林值。