简体   繁体   English

使用Autofac解决实体框架TPH继承的依赖关系的设计模式

[英]Design Patterns to resolve dependency using Autofac for Entity Framework TPH inheritance

I have used TPH in Entity Framework to create the Inventory table in my database. 我已经在实体框架中使用TPH在数据库中创建库存表。

public abstract class Inventory
{
    public Guid Id { get; set; }
    public DateTime On { get; set; }
}
public class CycleCountInventory : Inventory
{
    public string Frequency { get; set; }
    // and other properties
}
public class SkuGroupInventory : Inventory
{
    public string SkuGroup { get; set; }
    // and other properties
}

I have a requirement where items can be added to the inventory. 我有一项要求,可以将物品添加到库存中。 However, the behaviour of the inventory repo should be different based on the type of inventory. 但是,根据库存类型,库存回购的行为应有所不同。 I have a service class that holds a reference to the repo as follows: 我有一个服务类,其中包含对仓库的引用,如下所示:

public class InventoryService : IInventoryService
{

    public bool AddItems(Inventory inventory, IList<Guid> itemsGuidList)
    {
        // the inventory type is only known at this point

        IInventoryRepo repo = (inventory is SkuGroupInventory)
            ? (IInventoryRepo) new SkuGroupInventoryRepo()
            : new CycleCountInventoryRepo();

        return repo.PerformInventory(itemsGuidList);
    }

}

Currently I am loading the different implementations of IInventoryRepo by manually doing a check. 目前,我正在通过手动执行检查来加载IInventoryRepo的不同实现。 There are a few problems with this approach: 这种方法存在一些问题:
1. I have using Autofac to resolve all dependencies... this approach makes my code hard to test 1.我已经使用Autofac来解决所有依赖关系...这种方法使我的代码难以测试
2. As more types of inventories are added, my code will become hard to manage 2.随着添加更多类型的清单,我的代码将变得难以管理

Are there any patterns (Abstract Factory / Strategy etc) I can use to delegate resolving the dependencies back to Autofac. 是否有任何模式(抽象工厂/策略等)可用于委托将依赖项解析回Autofac。 I am sure someone would have faced this before. 我敢肯定有人会遇到这个问题。 Thanks! 谢谢!

You can use a factory pattern here. 您可以在此处使用工厂模式。

public interface IInventoryFactory 
{
 // instead of type, you could also have a discriminator on the
 // inventory class, to give its specific type. (enum etc.)
 IInventoryRepo CreateInventoryRepo(Type inventoryType);
}

public class MyInventoryFactory : IInventoryFactory 
{
 // instead of type, you could also have a discriminator on the
 // inventory class, to give its specific type. (enum etc.)
 public IInventoryRepo CreateInventoryRepo(Type inventoryType)
 {
   IInventoryRepo repo = (inventoryType == typeof(SkuGroupInventory))
        ? (IInventoryRepo) new SkuGroupInventoryRepo()
        : new CycleCountInventoryRepo();

   return repo;
 }
}

public class InventoryService : IInventoryService
{
    private readonly IInventoryFactory _inventoryFactory;

    public InventoryService(IInventoryFactory inventoryFactory)
    {
     _inventoryFactory = inventoryFactory;
    }

    public bool AddItems(Inventory inventory, IList<Guid> itemsGuidList)
    {
        // create the right repo based on type of inventory.
        // defer it to the factory

        IInventoryRepo repo = _inventoryFactory.CreateInventoryRepo(inventory.GetType());

        return repo.PerformInventory(itemsGuidList);
    }
 }

The real concrete implementation of the factory will be injected by Autofac, so register it in Autofac. 工厂的实际具体实现将由Autofac注入,因此请在Autofac中进行注册。 This Service class method is now unit testable since you can mock the factory. 由于可以模拟工厂,因此此Service类方法现在可以进行单元测试。

And the factory itself is unit testable since you just need to pass in the appropriate 'inventory' instances to assert the right concrete repos. 而且工厂本身可以进行单元测试,因为您只需要传递适当的“库存”实例来声明正确的具体存储库即可。

ps please note that Autofac doesn't even need the factory interface/concrete class. ps请注意,Autofac甚至不需要工厂接口/混凝土类。 it can inject automatic factories for you. 它可以为您注入自动工厂。 But it is just a preference of people to use Autofac automatic factories vs explicit interface based factories. 但是使用Autofac自动工厂还是使用基于显式界面的工厂只是人们的偏爱。 Whichever you prefer. 无论您喜欢哪个。

also, a GetType is slightly performance intensive call.. in production scenarios, if your AddItems method is called several thousand times, a GetType is not a good FIRST option.. a lot of folks solve it as follows: 同样,GetType会稍微提高性能。.在生产场景中,如果您的AddItems方法被调用了数千次,则GetType并不是一个很好的FIRST选项。.很多人如下解决它:

  1. Add an abstract getter only enum called inventoryType to the abstract Inventory Class 向抽象Inventory类添加一个仅称为getterType的抽象获取方法枚举

  2. Have the enum definition values as CycleCount, SkuGroup etc. 枚举定义值为CycleCount,SkuGroup等。

  3. Override the enum getter in the concrete child classes with their specific types. 用具体的类型重写具体子类中的枚举获取器。

  4. Once this happens, the CreateInventoryRepo method can take this enum as the parameter. 一旦发生这种情况,CreateInventoryRepo方法可以将此枚举作为参数。

 public IInventoryRepo CreateInventoryRepo(InventoryType inventoryType) { IInventoryRepo repo = (inventoryType == InventoryType.SkuGroup) ? (IInventoryRepo) new SkuGroupInventoryRepo() : new CycleCountInventoryRepo(); return repo; } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM