延迟加载而不使用lazy <t> </t>

时间:2014-06-20 17:11:47

标签: c#

我有:

类别类

 public partial class Category : BaseEntity
    {
        ...
        public string Name { get; set; }
        private ICollection<Discount> _appliedDiscounts;
        public virtual ICollection<Discount> AppliedDiscounts
        {
            get { return _appliedDiscounts ?? (_appliedDiscounts = new List<Discount>()); }
            protected set { _appliedDiscounts = value; }
        }
}

服务:

public IList<Category> GetCategories()
{
   // ado.net to return category entities.

}
public ICollection<Discount> GetDiscount(int categoryId)
{
   // ado.net .

}

我不想像EF那样使用ORM ..但是简单的ado.net,我不想在我的域名定义中加入丑陋的Lazy<T>,例如公共懒惰....

那么在这种情况下,如何在不使用Category类的Lazy<T>声明的情况下自动将LinkedDiscounts绑定到GetDiscount?

1 个答案:

答案 0 :(得分:2)

我不知道你为什么不喜欢Lazy<T>类型 - 这很简单,很有用,你不用担心任何事情。

没有人强迫你使用public Lazy<IEnumerable<Discount>> GetDiscounts();

您可以在内部使用它:

Lazy<IEnumerable<Discount>> discounts = new Lazy<IEnumerable<Discount>>(() => new DiscountCollection());

public IEnumerable<Discount> GetDiscounts()
{
   return discounts.Value;
}

它按预期运作 - 直到没有人要求折扣才能创造。

如果你真的想要 - 你可以创建自己的实现。像里希特的单身人士课程&#34; CLR通过C#&#34; book(因为Lazy具有适当的单例容器的所有属性 - 线程安全性,只能评估一个内部&#39; singleton&#39;值的实例...)。

但你真的想创造并测试吗?您只需将一个精心设计的标准组件替换为可疑的标准组件。

在实际阅读您的问题之后

1)如果您的延迟加载不需要任何线程安全,即使没有任何Lazy或复杂结构,您也可以完成类似的行为 - 只需使用Func委托:

public partial class Category : BaseEntity
    {
        ...
        private Func<ICollection<Discount>> getDiscounts;

        public Category(Func<ICollection<Discount>> getDiscounts) { ... }

        public string Name { get; set; }
        private ICollection<Discount> _appliedDiscounts;
        public virtual ICollection<Discount> AppliedDiscounts
        {
            get { return _appliedDiscounts ??
 (_appliedDiscounts = new List<Discount>(this.getDiscounts())); }
            protected set { _appliedDiscounts = value; }
        }
}

public IList<Category> GetCategories()
{
   // ado.net to return category entities.
   ... = new Category(() => this.GetDiscount((Int32)curDataObject["categoryId"]))

}
public ICollection<Discount> GetDiscount(int categoryId)
{
   // ado.net .
}

如果您注入服务,那将更加简单:

        public virtual ICollection<Discount> AppliedDiscounts
        {
            get { return _appliedDiscounts ?? 
(_appliedDiscounts = new List<Discount>(this.service.GetDiscounts(this.CategoryId))); }
            protected set { _appliedDiscounts = value; }
        }

2)如果你需要在多个线程中使用这些对象,那么你将不得不重新设计你的类 - 它们看起来不像线程安全。

评论后

  

我想做的就是这个人   stackoverflow.com/questions/8188546 / ...我想知道这个概念是怎么回事   像EF这样的ORM对域进行处理,保持清洁并与之分离   注入服务类但仍然能够处理延迟加载。我知道   我可以使用Reflection来获取所有对象属性及其对象   变量(如AppliedDiscounts),但不要&#39;知道如何改造   这些动态变为惰性类型,以便以后可以加载   需要的。

普遍的原则是,你无法得到任何东西。你不能让你的实体干净并与任何服务分开(甚至通过一些代理),并允许他们懒得加载 - 如果他们不了解服务和服务,就不知道关于他们的任何事情然后如何延迟加载工作?没有办法实现这样的绝对解耦(对于两个组件进行交互,他们必须要么彼此了解,知道某些第三个模块 - 通信器,或者某些模块应该知道它们。但是这种耦合可能部分或完全隐藏。

提供实体对象模型的技术通常使用以下某些技术:

  1. 生成代码以在简单数据对象或接口的实体实例之上创建包装器(或代理)。它可能是C#代码或IL编织,它甚至可能是在运行时使用Reflection.Emit之类的东西动态创建的内存中程序集。这不是最简单或最直接的方法,但它将为您提供巨大的代码调整功能。很多现代框架都使用它。
  2. 在Context类中实现所有这些功能 - 您不会在最终对象中进行延迟加载,您必须在Context类中明确使用它:context.Orders.With("OrderDetails")。积极的一面是实体将是干净的。
  3. 注入服务(或仅注入其操作所需的子集) - 这是您希望避免的。
  4. 使用事件或其他类似观察者的模式 - 您的实体 将从服务逻辑和依赖中清除(至少在某些情况下) 感觉),但将包含一些不会成为的连接基础设施 非常直接或易于管理。
  5. 对于您的自定义对象模型2或3是最好的投注。但你可以尝试Roslyn

    1