【问题标题】:c# generic types and repository patternc# 泛型类型和存储库模式
【发布时间】:2015-10-06 13:27:09
【问题描述】:

我正在使用存储库模式开发 C# MVC 应用程序。我使用 Unity 作为我的 IoC,以便在 MVC 应用程序中实现我的存储库。

我创建了以下泛型类型,目的是最大限度地减少整个应用程序中的代码复制。这是一个示例:

public abstract class GenericRepository<T, C> : IDisposable,IGenericRepository<T> where T : class where C : DbContext, new()


public async void AddObjectAsync<T>(T entity) where T : class
    {
        try
        {
            // Validate that that there is not an existing object in the database.
            var x = _context.Entry(entity);
            if (!Exists(entity))
            {
                _context.Set<T>().Add(entity); // Add the entry if it does not exist.
                _context.SaveChanges();
            }
            else
            {
                UpdateObjectAsync(entity); // Update the entry if it did exist.
            }
        }
        catch
        {
            throw;
        }

这在我使用 TPC 或 TPH 策略时效果很好,但它不适用于 TPT 策略。一个例子:

public abstract class Component
{
    [Key]
    public Guid ComponentId { get; set; }

    public string Manufacturer { get; set; }
}
public class SpecialComponent : Component
{
    public string ExtraSpecialProperty { get; set; }
}

我在 ComponentRepository 中的实现:

public class ComponentRepository : GenericRepository<Component, HappyDbContext>, IComponentRepository
{
public async void AddComponentAsync<T>(T component) where T : class
    {
        try
        {

            if(component != null)
            {
                AddObjectAsync(component);
            }
            else
            {
            throw new ArgumentNullException();
            }

        }
        catch (ArgumentNullException ex)
        {
            _logger.WriteErrorLogAsync(ex);
            throw ex;
        }
    }

这个代码块的第一行是我遇到的问题。为了初始化 GenericRepository 类型,我需要为 T 插入一个类。在这种情况下,DbContext C 将始终相同,因此无需担心。

如何实现适用于继承类型的完全通用模式?如果是少量物品,那么我就不那么担心了,但是在这种情况下并非如此。我认为肯定有更好的方法来处理这个问题,所以我向大家征求意见。

【问题讨论】:

  • GenericRepository 类的T 参数和AddObjectAsync 的T 参数是什么关系?
  • 在这种情况下您可以使用组合而不是继承吗?如果 ComponentRepository 注入了一个能够构造 GenericRepository 实例的专用工厂,那么AddComponentAsync 可以调用该工厂以根据提供给该方法的类型构造一个强泛型存储库。
  • 对不起,我误读了您的评论。他们是一样的。如果我们传递实体“组件”,则 AddObjectAsync 将是 类型,并期望(组件实体)的方法参数。
  • @StriplingWarrior 这是一个非常有趣的建议,今晚我将对其进行调查,并让您知道它是否适用于我的模型。我正在想象某种基于服务的方法,这很可能是答案。如果我不是一个完整的新手,我可能会更快地告诉你!感谢您迄今为止的意见。
  • 如果两个T 类型相同,则该方法不需要在该级别是通用的。 public async void AddObjectAsync(T entity) {..} 可以正常工作。

标签: c# asp.net-mvc entity-framework generics


【解决方案1】:

看起来你可能有“过度通用”的情况。

如果将DbContext 硬编码在两个地方,那么将其设为泛型似乎是在浪费时间。即GenericRepository&lt;Component, HappyDbContext&gt;where C : DbContext, new()。强类型化字段 _context 并使用来自强类型存储库的 Unity 注入 HappyDbContext 可能更有意义。

将通用实体类型下移到方法级别而不是类也可能会简化事情:

public interface IGenericRepository
{
    void AddObjectAsync<T>(T entity) where T : class;
}

public class GenericRepository : IGenericRepository
{
    private readonly DbContext _context;

    public GenericRepository(DbContext context)
    {
        _context = context;
    }

    ....

    public async void AddObjectAsync<T>(T entity) where T : class
    {
        // Validate that that there is not an existing object in the database.
        var x = _context.Entry(entity);
        if (!Exists(entity))
        {
            _context.Set<T>().Add(entity); // Add the entry if it does not exist.
            _context.SaveChanges();
        }
        else
        {
            UpdateObjectAsync(entity); // Update the entry if it did exist.
        }
    }
}

public interface IComponentRepository
{
    void AddComponentAsync(Component component);
    // or void AddComponentAsync<T>(T component);
    // depends if you'll be reusing the ComponentRepository 
    // for types that inherit Component but still have individual tables... 
    // It was a little difficult to tell from your example.
}

public class ComponentRepository : GenericRepository, IComponentRepository
{
    public ComponentRepository(DbContext context) : base(context) { }

    ...

    public async void AddComponentAsync(Component component)
    {
        try
        {
            if (component == null) throw new ArgumentNullException();
            AddObjectAsync(component);
        }
        catch (ArgumentNullException ex)
        {
            _logger.WriteErrorLogAsync(ex);
            throw ex;
        }
    }
}

希望这会有所帮助

【讨论】:

    猜你喜欢
    • 2018-05-27
    • 1970-01-01
    • 2013-11-21
    • 1970-01-01
    • 2018-10-30
    • 1970-01-01
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    相关资源
    最近更新 更多