【问题标题】:Why is my C# Inheritance not working with the Generic Repository Pattern为什么我的 C# 继承不适用于通用存储库模式
【发布时间】:2015-04-24 10:03:36
【问题描述】:

我已经定义了一个基础仓库如下:

public abstract class BaseRepository<TEntity> where TEntity : class
{
    protected DbSet<TEntity> dbSet;
    protected readonly DbContext dbContext;

    public BaseRepository()
    {
        this.dbContext = new SchoolDemoEntities();
        dbSet = dbContext.Set<TEntity>();
    }

    public BaseRepository(DbContext dbContext)
    {
        this.dbContext = dbContext;
        dbSet = dbContext.Set<TEntity>();
    }
}

以上是我所有其他存储库类的基类。其中之一是阅读...

public class ReadRepository<TEntity>
: BaseRepository<TEntity>
, IReadRepository<TEntity>
  where TEntity : class
{
    #region Constructors

    public ReadRepository() : base() { }

    public ReadRepository(DbContext dbContext)
        : base(dbContext) { }

    #endregion

    /// <summary>
    /// Maps to read functionality in the database. Reads a single record.
    /// </summary>
    /// <param name="id">an integer identifier which maps to the primary key</param>
    /// <returns>TEntity -> a single instance of the class</returns>
    public TEntity Read(int id)
    {
        return dbSet.Find(id);
    }
}

以上只是类的一部分,还有其他的读取方法。还有一个类(删除)继承了这个读取类...

public class DeleteRepository<TEntity>
: ReadRepository<TEntity>
, IDeleteRepository<TEntity>
  where TEntity : class
{
    #region Constructors

    public DeleteRepository() : base() { }

    public DeleteRepository(DbContext dbContext)
        : base(dbContext) { }

    /// <summary>
    /// Maps to delete functionality in the database. Deletes the given record.
    /// </summary>
    /// <param name="entity">A class containing the information to delete.</param>
    /// <returns>int: The number of records affected.</returns>

    #endregion


    public int Delete(TEntity entity)
    {
        dbSet.Remove(entity);
        return dbContext.SaveChanges();
    }
}

我的问题是,据我了解继承,当我在控制器中声明删除类的实例时,我应该可以访问 read 方法,如下所示:

public class CourseController : Controller
{
    IDeleteRepository<Course> deleteRepository = new DeleteRepository<Course>(new DbContext("SchoolDemoEntities"));

    // POST: Course/Delete/5
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public ActionResult DeleteConfirmed(int id)
    {
        //*** The line directly below doesn't work ***
        Course course = deleteRepository.Read(id);


        deleteRepository.Delete(course);
        return RedirectToAction("Index");
    }
}

突出显示的行不起作用。我看不出有什么问题。 C# 只是强调 read 方法说:

IDeleteRepository 不包含“读取”的定义,并且 没有扩展方法“读取”接受类型的第一个参数 可以找到“IDeleteRepository”(您是否缺少使用 指令还是程序集引用?)

我确实定义了接口,并且消息是正确的,它没有读取。但我不明白为什么我需要一个,因为 Read repo 实现了它自己的 read 方法,而这个具体的实现是由 delete 继承的。为什么我需要定义一个已经在我的读取接口和类中定义并继承的读取方法。

导致我出现此错误的原因是我试图通过与同一实体的多个连接来解决的问题。

如果我在控制器中明确定义读取类,如下所示:

    IReadRepository<Course> readRepository = new ReadRepository<Course>(new DbContext("SchoolDemoEntities"));

然后将突出显示的行更改为...

        Course course = readRepository.Read(id);

然后我得到错误...

无法删除该对象,因为它在 对象状态管理器。

这确实有意义,因此继承的原因。我需要在删除时阅读相同的连接。使用上述方法执行此操作会从读取中关闭连接并重新打开它以进行删除。我认为继承应该解决这个问题?但是当我继承时,我无法访问 read 方法并且无法理解为什么。

【问题讨论】:

  • 您是否为读取和删除操作使用单独的存储库?每个实体都应该有一个可以读取和删除的存储库。还是我误解了商业案例?

标签: c# asp.net-mvc repository-pattern


【解决方案1】:

DeleteRepository 包含 Read 方法,因为它继承自 ReadRepository

问题是你的局部变量是 IDeleteRepository&lt;Course&gt; 类型 - 这不是 IDeleteRepository&lt;Course&gt; 上的 Read 方法。

如果您将声明更改为正确的类型,您将可以访问这两种方法:

DeleteRepository<Course> deleteRepository = new DeleteRepository<Course>(new DbContext("SchoolDemoEntities"));

【讨论】:

  • 好的...所以因为我使用的是接口而不是具体的实现,这就是我遇到问题的原因...我教过我应该使用抽象,然后具体化。但感谢您的回答。
  • 这通常是个好建议。在这种情况下,我希望有一个带有ReadDeleteIRepository 接口,而不是两个单独的接口。
  • 感谢您的帮助...很有趣...它现在有效并且有意义! :) 我必须等待 4 分钟才能接受答案。
  • 如果你想让IDeleteRepsoitory也有Read,那么让接口派生自IReadRepository
  • 这样的问题是,每当我实现删除接口时,我都必须实现读取功能。我可能错了?
【解决方案2】:

如果Read()IReadRepository 上,让IDeleteRepository 继承自IReadRepository 以使您的接口层次结构与您的实现层次结构相匹配,那么这些方法将在您期望的级别上可见。

尽管正如@Charles Mager 在his answer 中所说,Read()Delete() 应该在基础存储库中,因为存储库模式应该为每个业务对象都有一个存储库,而不是存储库操作。

【讨论】:

  • 我在同一个界面上拥有所有 CRUD 操作的唯一问题是,即使不需要,我也必须在相关类中实现功能。例如,如果我想要读取所有内容或批量读取,我必须为其他操作和批量操作实现所有功能。但这只是我有限的知识。我可能错了。
  • 如果都是通用的,你可以在基础实现上实现它,并在所有派生类上免费获得它。如果它是唯一的或不应该存在于派生类中,您可以覆盖它。
  • 谢谢...这是我将探讨的内容...我按照您的建议做了,清理了很多代码。干杯。 +1
猜你喜欢
  • 1970-01-01
  • 2010-09-07
  • 1970-01-01
  • 2017-06-14
  • 1970-01-01
  • 2011-08-14
  • 1970-01-01
  • 2012-03-01
  • 2020-12-13
相关资源
最近更新 更多