【问题标题】:Design Patterns to resolve dependency using Autofac for Entity Framework TPH inheritance使用 Autofac 为实体框架 TPH 继承解决依赖关系的设计模式
【发布时间】:2016-02-17 11:53:44
【问题描述】:

我在 Entity Framework 中使用 TPH 在我的数据库中创建了 Inventory 表。

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
}

我有一个可以将物品添加到库存中的要求。但是,库存回购的行为应该根据库存类型而有所不同。我有一个包含对 repo 的引用的服务类,如下所示:

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);
    }

}

目前我正在通过手动检查加载IInventoryRepo 的不同实现。这种方法存在一些问题:
1. 我使用 Autofac 来解决所有依赖项......这种方法使我的代码难以测试
2.随着库存类型的增加,我的代码将变得难以管理

是否有任何模式(抽象工厂/策略等)我可以用来将解决依赖关系委托给 Autofac。我相信以前有人会遇到过这种情况。谢谢!

【问题讨论】:

    标签: c# entity-framework design-patterns autofac


    【解决方案1】:

    您可以在这里使用工厂模式。

    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);
        }
     }
    

    工厂真正的具体实现会被Autofac注入,所以在Autofac中注册。 这个 Service 类方法现在是可单元测试的,因为您可以模拟工厂。

    并且工厂本身是可单元测试的,因为您只需要传入适当的“库存”实例即可断言正确的具体存储库。

    附言请注意 Autofac 甚至不需要工厂接口/具体类。它可以为您注入自动化工厂。但这只是人们使用 Autofac 自动工厂与基于显式接口的工厂的偏好。 随你喜欢。

    另外,GetType 是稍微性能密集型的调用。在生产场景中,如果您的 AddItems 方法被调用数千次,GetType 不是一个好的 FIRST 选项。很多人这样解决它:

    1. 将名为inventoryType 的抽象getter 枚举添加到抽象Inventory 类

    2. 将枚举定义值设为 CycleCount、SkuGroup 等。

    3. 用具体子类的特定类型覆盖枚举 getter。

    4. 一旦发生这种情况,CreateInventoryRepo 方法可以将此枚举作为参数。

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

    【讨论】:

    • 我也在沿着同样的路线工作......很高兴知道我走在正确的道路上。
    • 酷。很高兴知道你也在同一条路上。只是一个 nit.. 将工厂命名为 IInventoryRepoFactory 因为它创建的是 Repo 而不是 Inventory
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    • 1970-01-01
    相关资源
    最近更新 更多