3

我最近查看了 Kazi Manzur Kigg MVC 实现(Kazi rock),并注意到一些似乎违反 DRY/SOC 原则的代码。我很想听听每个人对可能的重构以分离关注点的想法。

Kigg在每个存储库类上都实现了一个Add和方法(注意:具有虚拟方法,每个具体实现都可以重载。)RemoveBaseRepository

theKigg.Repository.LinqToSql.CategoryRepositoryKigg.Repository.LinqToSql.StoryRepositoryboth 级联的实现通过它们的Remove方法删除子实体。(注意:Category 与 Story 有父关系(一对多),因此它们从 Story 到对象图共享相同的子关系)见图表。有问题的代码是两个存储库相互删除子实体的方式:

类别存储库

namespace Kigg.Repository.LinqToSql.CategoryRepository{
    //using statements omitted
    public class CategoryRepository : BaseRepository<ICategory, Category>, ICategoryRepository
    {
    //code omitted

    public override void Remove(ICategory entity)
    {
        Check.Argument.IsNotNull(entity, "entity");

        Category category = (Category) entity;

        Database.DeleteAll(Database.StoryViewDataSource.Where(v => v.Story.CategoryId == category.Id));
        Database.DeleteAll(Database.CommentSubscribtionDataSource.Where(cs => cs.Story.CategoryId == category.Id));
        Database.DeleteAll(Database.CommentDataSource.Where(c => c.Story.CategoryId == category.Id));
        Database.DeleteAll(Database.VoteDataSource.Where(v => v.Story.CategoryId == category.Id));
        Database.DeleteAll(Database.MarkAsSpamDataSource.Where(sp => sp.Story.CategoryId == category.Id));
        Database.DeleteAll(Database.StoryTagDataSource.Where(st => st.Story.CategoryId == category.Id));
        Database.DeleteAll(Database.StoryDataSource.Where(s => s.CategoryId == category.Id));

        base.Remove(category);
    }
}
}

故事库

namespace Kigg.Repository.LinqToSql
{

    //using statements omitted


    public class StoryRepository : BaseRepository<IStory, Story>, IStoryRepository
    {

    //code omitted


    public override void Remove(IStory entity)
    {
        Check.Argument.IsNotNull(entity, "entity");

        Story story = (Story) entity;

        Database.DeleteAll(Database.StoryViewDataSource.Where(sv => sv.StoryId == story.Id));
        Database.DeleteAll(Database.CommentSubscribtionDataSource.Where(cs => cs.StoryId == story.Id));
        Database.DeleteAll(Database.CommentDataSource.Where(c => c.StoryId == story.Id));
        Database.DeleteAll(Database.VoteDataSource.Where(v => v.StoryId == story.Id));
        Database.DeleteAll(Database.MarkAsSpamDataSource.Where(sp => sp.StoryId == story.Id));
        Database.DeleteAll(Database.StoryTagDataSource.Where(st => st.StoryId == story.Id));

        base.Remove(story);
    }
    }

}

假设更好的设计会在 上CategoryRepository调用Remove方法StoryRepository,从而将 Story 的子对象删除的关注委托给StoryRepository它所属的位置,我是否正确?从维护的角度来看,对 Story 的孩子的任何添加都需要将DeleteAll调用添加到 theCategoryRepositoryStoryRepository.

什么是更好的实施方式?

是否应该CategoryRepository重构以StoryRepository直接使用?: CategoryRepository(重构)

namespace Kigg.Repository.LinqToSql.CategoryRepository{
    //using statements omitted
    public class CategoryRepository : BaseRepository<ICategory, Category>, ICategoryRepository
    {
    //code omitted

    public override void Remove(ICategory entity)
    {
        Check.Argument.IsNotNull(entity, "entity");

        Category category = (Category) entity;

        // refactor - start
        StoryRepository _storyRepository = new StoryRepository( Database );
        category.Stories.ForEach( story => _storyRepository.Remove( story ) );
        // refactor - end

        base.Remove(category);
    }
}
}

此重构将允许CategoryRepository重用 中的删除逻辑,并且还应该重用由给定构造函数的参数引用StoryRepository的相同 LinqToSql 。但是当涉及到单元测试时,它开始有异味。DataContextDatabaseStoryRepository

更好的重构是否包括使用 IoC(Kigg 使用 Unity 作为其 Ioc 容器)将PerWebRequest作用域实例注入IStoryRepositoryCategoryRepository的构造函数中?

CategoryRepository(重构采取 2)

namespace Kigg.Repository.LinqToSql.CategoryRepository{
    //using statements omitted
    public class CategoryRepository : BaseRepository<ICategory, Category>, ICategoryRepository
    {


    private readonly IStoryRepository _storyRepository;

    public CategoryRepository(IDatabase database, IStoryRepository storyRepository) : base(database)
    {
        Check.Argument.IsNotNull(storyRepository, "storyRepository");
        _storyRepository = storyRepository;
    }

    public CategoryRepository(IDatabaseFactory factory, IStoryRepository storyRepository) : base(factory)
    {
        Check.Argument.IsNotNull(storyRepository, "storyRepository");
        _storyRepository = storyRepository;
    }

    //code omitted

    public override void Remove(ICategory entity)
    {
        {
        Check.Argument.IsNotNull(entity, "entity");

        Category category = (Category) entity;

        // refactor - start
        category.Stories.ForEach( story => _storyRepository.Remove( story ) );
        // refactor - end

        base.Remove(category);
    }
}
}

通过第二次重构,我们现在可以在单元测试期间和通过 Unity IocIStoryRepository注入的实例。CategoryRepository当然,我们必须将此重构扩展到每个存储库类,以便他们可以倾向于自己孩子的责任。

大家的想法是什么?

4

2 回答 2

1

请原谅我对 L2S 的无知(我使用 NHibernate),但它不会自动处理级联吗?

于 2009-07-17T02:44:08.660 回答
1

JBland、LingToSql 将处理数据库中定义的级联。虽然,SQL Server 不允许多个级联路径

Kigg 数据库没有定义级联删除或更新规则,但如果存储库实现执行必要的删除,则不需要它们。

于 2009-07-17T09:56:03.817 回答