如何通过接口、基础和具体实现存储库模式

发布于 2024-07-20 06:20:24 字数 2619 浏览 2 评论 0 原文

我几乎已经通过一个 IRepository 接口、一个 NewsRepository 类和一个 News 实体完成了我的存储库模式的实现。 我遇到的问题是尝试将通用方法抽象为基本存储库类。

我找不到在 NewsRepository 中抽象 Get 方法的方法,因为它包含特定的 Linq 表达式。

我的问题是

1)我如何将public T Get(int id)方法抽象为基类? 到目前为止,我做到这一点的唯一方法是传入 Expression> 而不是 int,但是这个 deosn 并没有真正抽象出每个子的常见行为类仍然需要传递一个在每种情况下几乎相同的表达式,即 n =>; n.id == id

2) 如何将子类 GetViolations 和映射方法传递到基类的 Update 方法中? 我想解决方案可能是通过使用委托,但我无法获得编译语法

这是一组简化的代码 - 实际上我有一个 Save 方法,它执行更新和插入,而不仅仅是此处显示的更新。

public interface IRepository<T>
{
    T Get(int id);
    void Update(T item);
}

public class NewsRepository : IRepository<News>
{
    private Table<News> _newsTable;
    public NewsRepository(string connectionString)
    {
        _newsTable = new DataContext(connectionString).GetTable<News>();
    }

    public News Get(int id)
    {
        return _newsTable.SingleOrDefault(n => n.NewsId == id);
    }

    public void Update(News item)
    {
        var errors = item.GetRuleViolations();
        if (errors.Count > 0)
            throw new RuleException(errors);

        News dbNews = _newsTable.SingleOrDefault(n => n.NewsId == item.NewsId);
        map(dbNews, item);

        _newsTable.Context.SubmitChanges();
    }

    private void map(News dbNews, News news)
    {
        dbNews.Title = news.Title;
        dbNews.Article = news.Article;
    }
}

public class Repository<T> where T : class
{
    protected Table<T> _table;

    public Repository(Table<T> t)
    {
        _table = t;
    }

    //How do i do this??! - This doesn't compile due to T no having a NewsId
    public T Get(int id)
    {
    return _table.SingleOrDefault(n => n.NewsId == id);
    }

    //This seems to be a solution, but it's not really abstracting common behaviour as each
    //sub-class will still need to pass in the same linq expression...
    public T Get(Expression<Func<T,bool>> ex)
    {
        return _table.SingleOrDefault(ex);
    }

    public void Update(T item)
    {
        //How is it possible to pass in the GetRuleViolations and map functions to this method?
        var errors = item.GetRuleViolations();
        if (errors.Count > 0)
            throw new RuleException(errors);

        T dbNews = _table.SingleOrDefault(n => n.NewsId == item.NewsId);
        map(dbNews, item);

        _table.Context.SubmitChanges();
    }
}

I have almost completed implementing my repository pattern by having a IRepository<T> interface, a NewsRepository class and a News entity. The problem I ran into was trying to abstract out common methods to a base Repository class.

I could not find a way to abstract the Get method in the NewsRepository as it contains a specific Linq expression.

My questions are:

1) How do I abstract to a base class the public T Get(int id) method please? The only way I have done it so far is by passing in Expression<Func<T,bool>> instead of an int, but then that deosn't really abstract out common behaviour as each sub-class will still need to pass in an expression that is almost identical in each case ie n => n.id == id.

2) How do I pass into the base class on the Update method the sub-class GetViolations and map methods please? I imagine the solution is possibly by using delegates, but I couldn't get the syntax to compile

This is a simplified set of the code - in practice I have a Save method which does Update and Insert rather than just the Update shown here.

public interface IRepository<T>
{
    T Get(int id);
    void Update(T item);
}

public class NewsRepository : IRepository<News>
{
    private Table<News> _newsTable;
    public NewsRepository(string connectionString)
    {
        _newsTable = new DataContext(connectionString).GetTable<News>();
    }

    public News Get(int id)
    {
        return _newsTable.SingleOrDefault(n => n.NewsId == id);
    }

    public void Update(News item)
    {
        var errors = item.GetRuleViolations();
        if (errors.Count > 0)
            throw new RuleException(errors);

        News dbNews = _newsTable.SingleOrDefault(n => n.NewsId == item.NewsId);
        map(dbNews, item);

        _newsTable.Context.SubmitChanges();
    }

    private void map(News dbNews, News news)
    {
        dbNews.Title = news.Title;
        dbNews.Article = news.Article;
    }
}

public class Repository<T> where T : class
{
    protected Table<T> _table;

    public Repository(Table<T> t)
    {
        _table = t;
    }

    //How do i do this??! - This doesn't compile due to T no having a NewsId
    public T Get(int id)
    {
    return _table.SingleOrDefault(n => n.NewsId == id);
    }

    //This seems to be a solution, but it's not really abstracting common behaviour as each
    //sub-class will still need to pass in the same linq expression...
    public T Get(Expression<Func<T,bool>> ex)
    {
        return _table.SingleOrDefault(ex);
    }

    public void Update(T item)
    {
        //How is it possible to pass in the GetRuleViolations and map functions to this method?
        var errors = item.GetRuleViolations();
        if (errors.Count > 0)
            throw new RuleException(errors);

        T dbNews = _table.SingleOrDefault(n => n.NewsId == item.NewsId);
        map(dbNews, item);

        _table.Context.SubmitChanges();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无名指的心愿 2024-07-27 06:20:24
  1. L2S 既不支持层超类型,也不支持在查询中使用接口成员,这使得重用变得相当困难。 一种选择是动态构建表达式树。 这有点混乱,但是如果将其隔离到基类存储库中,那就没那么糟糕了。

这是一个示例:

public interface IEntity
{
    int Id { get; }
}

public partial class News : IEntity
{
}

public class Repository<T> where T : class, IEntity
{

    private readonly DataContext _db;

    public Repository(DataContext db)
    {
        _db = db;
    }

    public T Get(int id)
    {
        Expression<Func<T, bool>> hasId = HasId(id);
        return _db.GetTable<T>().Single(hasId);
    }

    // entity => entity.Id == id;   
    private Expression<Func<T, bool>> HasId(int id)
    {
        ParameterExpression entityParameter = Expression.Parameter(typeof (T), "entity");
        return Expression.Lambda<Func<T, bool>>(
            Expression.Equal(
                Expression.Property(entityParameter, "Id"),
                Expression.Constant(id)
                ),
            new[] {entityParameter}
            );
    }
}

另请参阅 http://msdn.microsoft.com/en -us/library/bb397951.aspx

  1. L2S supports neither layer supertypes nor using interface members in queries, which makes reuse quite difficult. One option is to dynamically build an expression tree. It's a bit messy, but if you isolate it to your base class repository it's not that bad.

Here is an example:

public interface IEntity
{
    int Id { get; }
}

public partial class News : IEntity
{
}

public class Repository<T> where T : class, IEntity
{

    private readonly DataContext _db;

    public Repository(DataContext db)
    {
        _db = db;
    }

    public T Get(int id)
    {
        Expression<Func<T, bool>> hasId = HasId(id);
        return _db.GetTable<T>().Single(hasId);
    }

    // entity => entity.Id == id;   
    private Expression<Func<T, bool>> HasId(int id)
    {
        ParameterExpression entityParameter = Expression.Parameter(typeof (T), "entity");
        return Expression.Lambda<Func<T, bool>>(
            Expression.Equal(
                Expression.Property(entityParameter, "Id"),
                Expression.Constant(id)
                ),
            new[] {entityParameter}
            );
    }
}

See also http://msdn.microsoft.com/en-us/library/bb397951.aspx

月亮邮递员 2024-07-27 06:20:24
  1. 拥有实体的层超类型。 他们将共享一个 Id 属性。 您不必处理表示 id 属性的表达式,您只需知道它是什么即可。

  2. 模板方法模式。 在此模式中,您的基本 Update 会按顺序执行调用帮助器方法的所有工作,并且您的派生类实现这些受保护的抽象帮助器方法。

  1. It really helps to have a layer supertype for entities. They will share an Id property. You won't have to deal with an expression to represent the id proeprty, you'll just know what it is.

  2. The template method pattern. In this pattern your base Update does all the work calling helper methods in order, and your derived classes implement those protected abstract helper methods.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文