使用存根实体
假设我们在多对多关系中有 Product
s 和 Category
s:
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();
(其中 db
是 DbContext
的子类)。
这会在 Product
和 Category
之间的联结表中创建一条记录。但是,此表仅包含两个 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));
同样,这不会将完整实体加载到内存中。它有效地查询联结表,只返回一个布尔值。