C# 存储库模式:模型关系的实现和延迟加载
我有一个处理产品和产品类别的应用程序。对于其中的每一个,我都使用POCO定义了模型C# 存储库模式:模型关系的实现和延迟加载,c#,design-patterns,repository,lazy-loading,entity-relationship,C#,Design Patterns,Repository,Lazy Loading,Entity Relationship,我有一个处理产品和产品类别的应用程序。对于其中的每一个,我都使用POCO定义了模型 // Represents a product. class Product { public virtual int ID { get; set; } public virtual string Name { get; set; } public virtual ProductCategory Category { get; set; } } // Represents a product cat
// Represents a product.
class Product {
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual ProductCategory Category { get; set; }
}
// Represents a product category.
class ProductCategory {
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual IEnumerable<Product> Products { get; set; }
}
//表示一个产品。
类产品{
公共虚拟整数ID{get;set;}
公共虚拟字符串名称{get;set;}
公共虚拟产品类别{get;set;}
}
//表示产品类别。
类别ProductCategory{
公共虚拟整数ID{get;set;}
公共虚拟字符串名称{get;set;}
公共虚拟IEnumerable乘积{get;set;}
}
应用程序使用存储库访问这些模型
// The interface implemented by the application's repository
interface IProductRepository {
IEnumerable<Product> GetAllProducts();
void Add(Product product);
void Remove(Product product);
void Save(Product product);
}
//应用程序存储库实现的接口
接口知识库{
IEnumerable GetAllProducts();
无效添加(产品);
消除空洞(产品);
作废保存(产品);
}
在Product类中,仅当需要/访问ProductCategory类型的名为Category的属性时,才应加载该属性(延迟加载)。我希望我的模型保持POCO,并且只包含模型的结构
我是否采取了正确的方法?我是否应该在产品类中只有类别的ID,并使用单独的产品类别存储库来加载类别 实现延迟加载和关系
现在,我的repository接口实现返回的对象类型扩展了产品类型,并支持通过repository实例进行延迟加载 谁应负责装载产品类别 我感兴趣的是产品和类别存储库应该如何交互以实现延迟加载?它们应该相互引用,还是应该有一个包含两个子存储库的主存储库并将其传递给扩展模型类型 你会采取什么方法?(欢迎任何建议和批评)
我应该注意到,我希望应用程序是可扩展的,存储库和模型本身的所有接口都将在一个单独的组件中。这意味着扩展器将无法直接访问模型类定义。我正在做一些非常类似的事情,在我的例子中,我有产品和产品类别的存储库。存储库之外没有人知道如何加载东西——不管是懒惰还是其他什么——因此,如果需要,您可以稍后更改它。在我的例子中,我急切地加载类别,因为它们被访问的次数太多了,我按需加载产品并将其缓存一个小时左右。NHibernate支持通过代理对象(默认情况下使用)延迟加载,代理对象是存储库操纵的类的子类。NHibernate要求您将成员标记为
virtual
,以支持此方案。我不确定什么组件在需要时启动加载调用,但怀疑是代理实例
我个人认为,将成员标记为virtual
对于延迟加载功能来说是一个很小的代价
我想让我的模特保持POCO和
仅包含
模型
我会问,为什么数据的形状对这些类很重要
一般来说,这意味着您只需将我们的数据库模式直接公开给整个应用程序,并在其上加上一层非常薄的“模型”
我建议一个实体包含的数据是私有的,应该进行封装,行为应该是实体关注的焦点
此外,一次加载所需的所有数据更简单、更清晰。如果潜在的数据量太多,那么我建议您将太多的责任分配给一个实体,您需要进一步完善您的模型,或者添加一种机制,根据您使用实体的上下文检索实体
我的意思是,如果要查询以显示数据,则需要公开一些数据集。您可以在另一个上下文中查询类似但不同的数据集。进一步说,如果您需要执行操作或修改,您的实体需要公开特定的行为。但是在不同的上下文中——当您检索实体以执行不同的操作或修改时,您需要公开不同的特定行为
试图将所有这些不同的用途结合到一个单一的契约或接口中,或多或少会产生上帝对象实体
对于某些显示和某些操作,您只需要该类别集合。它只会让人一直暴露在外而感到痛苦。几句话和我的观点: 1) 我应该只知道那个人的身份证吗 产品类别中的类别和用途 产品的独立存储库 要加载类别的类别 不,您正在使用一个ORM(至少我假设您是这样做的),以便能够通过类实例之间的引用来建模关系,而不是通过您正在使用的ID来以关系方式进行查询。最后一个结果是,从模型类中删除所有导航属性,并且只有标量属性,其中一些属性充当对象之间的键。这只是ORM中的“R” 2) 就目前而言,我实施 存储库接口返回一个对象 属于扩展产品的类型 类型并支持延迟加载 通过存储库实例 我不知道这到底意味着什么。(我想看看代码片段是如何做到这一点的。)但我的猜测是,在派生的
产品类中,您以某种方式向存储库注入了一个引用,如下所示:
public class ProductProxy : Product
{
private IProductRepository _productRepo;
public ProductProxy(IProductRepository productRepo)
{
_productRepo = productRepo;
}
// now you use _productRepo to lazily load something on request, do you?
}
嗯,现在加载类别显然是个问题,因为IProductRepository
没有访问它们的方法
3)
我感兴趣的是产品和
C
public class ProductProxy : Product
{
private IUnitOfWork _unitOfWork;
public ProductProxy(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public Category Category
{
get
{
// ...
var productRepo = _unitOfWork.CreateGenericRepo<Product>();
var categoryRepo = _unitOfWork.CreateGenericRepo<Category>();
// you can pull out the repos you need and work with them
}
set { ... }
}
}