利用控制器和视图中的继承?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (111)

我刚才在codereview.stackexchange.com上发布了这篇评论 ......我觉得它可能更适合stackoverflow,因为它更像是一个问题,而不是代码审查。

它需要一些解释,所以请耐心等待。

我正在ASP.NET MVC中开发一个电子商务网站。用户可以在网站上发布不同类型的广告。

我使用继承来定义我的广告类型,这个问题是利用层次结构来删除控制器和视图中重复的代码。

我有不同的广告类型:SimpleAdCarRealEstateRental

每个广告都源自AdBase,其具有所有常见属性:

public abstract class AdBase
{
    public long AdBaseId { get; set; }
    public bool IsActive { get; set; }
    public long UserId { get; set; }
    public string Title { get; set; }
    public short AdDurationInDays { get; set; }
    public string PhotosFolder { get; set; }
}

现在,其他广告来自此基类:

public class SimpleAd : AdBase
{
    public decimal Price { get; set; }
}

public class Car : AdBase
{
    public decimal Price { get; set; }
    public string Make { get; set; }
}

public class RealEstateRental : AdBase
{
    public decimal WeeklyRent { get; set; }
    public DateTime AvailableFrom { get; set; }
    public short NoOfBedrooms { get; set; }
    public short NoOfBathrooms { get; set; }
}

我正在使用Entity Framework与数据库进行交互,我使用的是工作单元和存储库模式:

我有一个抽象基础存储库(目的是避免为每种广告类型重写相同的函数,所以我在这里放了常用函数):

public interface IAdBaseRepository<TEntity> where TEntity : AdBase
{
    TEntity Get(long adBaseId);
}

public abstract class AdBaseRepository<TEntity> : IAdBaseRepository<TEntity> where TEntity : AdBase
{
    public AdBaseRepository(ApplicationDbContext context) : base(context)
    {
    }

    public TEntity Get(long adBaseId)
    {
        return Context.AdBase.OfType<TEntity>()
                  .Where(r => r.IsActive == true && r.AdBaseId == adBaseId)
                  .FirstOrDefault();
    }
}

其他广告存储库继承自上述类:

public interface ISimpleAdRepository : IAdBaseRepository<SimpleAd>
{
}

public class SimpleAdRepository : AdBaseRepository<SimpleAd>,
    ISimpleAdRepository
{
    public SimpleAdRepository(ApplicationDbContext context) : base(context)
    {
    }
}

public interface ICarRepository : IAdBaseRepository<Car>
{
}

public class CarRepository : AdBaseRepository<Car>,
    ICarRepository
{
    public CarRepository(ApplicationDbContext context) : base(context)
    {
    }
}

这是我的工作单位:

public class UnitOfWork : IUnitOfWork 
{
    protected readonly ApplicationDbContext Context;

    public UnitOfWork(ApplicationDbContext context)
    {
        Context = context;
        SimpleAd = new SimpleAdRepository(Context);
        RealEstateRental = new RealEstateRentalRepository(Context);
        Car = new CarRepository(Context);
    }

    public ISimpleAdRepository SimpleAd { get; private set; }
    public IRealEstateRentalRepository RealEstateRental { get; private set; }
    public ICarRepository Car { get; private set; }

    public int SaveChanges()
    {
        return Context.SaveChanges();
    }

    public void Dispose()
    {
        Context.Dispose();
    }
}

到目前为止,我对所有内容感到满意......但问题是我不知道如何在控制器和视图中利用这种继承层次结构。

目前,我有3个控制器:SimpleAdControllerCarControllerRealEstateRentalController

public class SimpleAdController : ControllerBase
{
    private IUnitOfWork _unitOfWork;

    public SimpleAdController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    [HttpGet]
    public ActionResult Display(long id)
    {
        SimpleAd simpleAd = _unitOfWork.SimpleAd.Get(id);
        /* 
         * I have not included my ViewModel Classes in this question to keep
         * it small, but the ViewModels follow the same inheritance pattern
         */
        var simpleAdDetailsViewModel = Mapper.Map<SimpleAdDetailsViewModel>(simpleAd);
        return View(simpleAdDetailsViewModel);
    }
}

CarController并且RealEstateRentalController具有类似的显示功能,除了广告的类型不同(例如CarController我有):

    public ActionResult Display(long id)
    {
        Car car = _unitOfWork.Car.Get(id);
        var carViewModel = Mapper.Map<CarViewModel>(car);
        return View(car);
    }

我想要实现的是创建一个AdBaseController将所有常用方法放入其中,如下所示:

public class AdBaseController : ControllerBase
{
    private IUnitOfWork _unitOfWork;

    public AdBaseController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    // Display for generic ad type
    [HttpGet]
    public ActionResult Display(long id)
    {
        // SimpleAd simpleAd = _unitOfWork.SimpleAd.Get(id);
        /* 
         * I need to replace the above line with a generic ad type... 
         * something like: _unitOfWork<TAd>.GenericAdRepository.Get(id)
         */

        // var simpleAdDetailsViewModel = Mapper.Map<SimpleAdDetailsViewModel>(simpleAd);
        // return View(simpleAdDetailsViewModel);
        /* 
         * similarly I have to replace the above 2 lines with a generic type
         */
    }
}

如果我执行上述操作,那么我的广告控制器可以继承它,我不需要在每一个中重复相同的显示方法......但是我需要制作我的UnitOfWork通用...或者有2个UoW(通用的和非通用的)...我不确定这是不是一个好主意?有关于AdBaseController?的任何建议

同样地,我在我的视图中重复了很多代码。例如,这是显示SimpleAdView

<div class="row">
    <div class="col-l">
        @*this partial view shows Ad photos and is common code for all ad types*@
        @Html.Partial("DisplayAd/_Photos", Model)
    </div>
    <div class="col-r">
        <div class="form-row">
            @*Common in all ads*@
            <h5>@Model.Title</h5>
        </div>

        @*showing ad specific fields here*@
        <div class="form-row">
            <h5 class="price">$@Model.Price</h5>
        </div>

        @*Ad heading is common among all ad types*@
        @Html.Partial("DisplayAd/_AdBaseHeading", Model)
    </div>
</div>
@*Ad Description is common among all ad types*@
@Html.Partial("DisplayAd/_Description", Model)

这是我的展示CarView

<div class="row">
    <div class="col-l">
        @*Common in all ads*@
        @Html.Partial("DisplayAd/_Photos", Model)
    </div>
    <div class="col-r">
        <div class="form-row">
            @*Common in all ads*@
            <h5>@Model.Title</h5>
        </div>

       @*Price and Make are specific to Car*@ 
        <div class="form-row">
            <h5 class="price">$@Model.Price</h5>
        </div>
        <div class="form-row">
            <h5 class="make">@Model.Make</h5>
        </div>

        @*Common in all ads*@ 
        @Html.Partial("DisplayAd/_AdBaseHeading", Model)
    </div>
</div>
@*Common in all ads*@
@Html.Partial("DisplayAd/_Description", Model)

同样,我觉得我在每个视图中重复了很多代码。我试图通过将它们放在常见的部分视图中来减少重复代码的数量。我不确定是否有更好的方法来做到这一点?

提问于
用户回答回答于

原谅我,如果我误解了但是如果你添加了一个genric UOW,在我看来你可以做这样的事情:我不明白为什么这样做会不好

public class AdBaseController : ControllerBase
{
    private IUnitOfWork _unitOfWork;

    public AdBaseController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public ActionResult GetDisplayAction<TAd, TViewModel>(long id)
    {
        SimpleAd simpleAd = _unitOfWork<TAd>.GenericAdRepository.Get(id)
        var viewModel = Mapper.Map<TViewModel>(simpleAd);         
        return View(viewModel);
    }
}

public class SimpleAdController : ControllerBase
{    
    public SimpleAdController(IUnitOfWork unitOfWork) : base(unitOfWork)
    {
    }

    [HttpGet]
    public ActionResult Display(long id)
    {
        return GetDisplayAction<AdType, ViewModelType>();
    }
}

所属标签

可能回答问题的人

  • Hanzo

    6 粉丝0 提问7 回答
  • Richel

    9 粉丝0 提问3 回答
  • mariolu

    31 粉丝0 提问2 回答
  • 上云小秘书

    15 粉丝0 提问2 回答

扫码关注云+社区

领取腾讯云代金券