【问题标题】:Architecture abstraction problem in Repository ASP.NET MVCRepository ASP.NET MVC 中的架构抽象问题
【发布时间】:2025-12-13 13:00:09
【问题描述】:

我正在 VS2008 上使用 MVC ASP.NET 3.5 SP1。
我正在寻找一种方法来抽象我的用户存储库中的这三种方法。

public User GetUser(Log log)
{
  return db.Users.FirstOrDefault(u => u.Logs.Any(l => l.id.Equals(log.id)));
}

public User GetUser(Product product)
{
  return db.Users.FirstOrDefault(u => u.Products.Any(pr => pr.id.Equals(product.id)));
}

public User GetUser(Photo photo)
{
  return db.Users.FirstOrDefault(u => u.Photos.Any(ph => ph.id.Equals(photo.id)));
}

我的 DB.edmx 包含模型

User    [id, username, ...]  
Product [id, name, ...]
Photo   [id, name, ...]
Log     [id, data, ...]

对于所有这些(以及未来)基于 model.id 搜索的方法,是否可能只有 ONE 方法?

【问题讨论】:

    标签: asp.net-mvc architecture data-modeling repository-pattern


    【解决方案1】:
    public User GetUser(Expression<Func<User, bool>> restriction)
    {
      return db.Users.Where(restriction).FirstOrDefault();
    }
    

    现在使用它:

    var u = Repository.GetUser(u => u.Logs.Any(l => l.id.Equals(log.id)));
    

    您也可以使用MSDynamicQuery

    using System.Linq.Dynamic;
    
    //...
    public User GetUser(string propertyName, int id)
    {
        var restriction = propertyName + ".Any(id = @0)";
        return db.Users.Where(restriction, id).FirstOrDefault();
    }
    
    var u = Repository.GetUser("Logs", log.id);
    

    我的语法可能不太正确,但你明白了。

    【讨论】:

    • 太棒了。但我需要一个“更自动化”的表达式,可能使用类名。
    • 然后使用 MS Dynamic LINQ 做同样的事情。我将更新示例。
    • 谢谢,我想我会试试你建议的最后一个。
    【解决方案2】:

    如果所有关联实体(日志、产品和照片)都将通过一个公共属性 (id INT) 进行搜索,那么也许您可以尝试这样的事情...

    首先,创建一个接口:

    public interface IUserAssociation
    {
        int id { get; }
    }
    

    那么这三个类中的每一个都会像这样实现这个接口:

    public partial class Product : IUserAssociation
    {
    }
    

    GetUser 方法如下所示:

    public User GetUser<T>(T entity) where T : IUserAssociation
    {
        var type = typeof(T);
        if (type == typeof(Log))
        {
            return db.Users.FirstOrDefault(u => u.Logs.Any(l => l.id.Equals(entity.id)));
        }
        else if (type == typeof(Product))
        {
            return db.Users.FirstOrDefault(u => u.Products.Any(pr => pr.id.Equals(entity.id)));
        }
        else if (type == typeof(Photo))
        {
            return db.Users.FirstOrDefault(u => u.Photos.Any(ph => ph.id.Equals(entity.id)));
        }
        else
        {
            throw new ArgumentException();
        }
    }
    

    然后您应该能够调用 GetUser 并通过一种方法将日志、照片或产品实体传递给它。它不是很优雅,但适用于这种特定情况。

    【讨论】:

      【解决方案3】:

      我更喜欢 Craig 的解决方案,但我建议这样做:

      Repository.GetUser(u => u.Logs, log);
      

      如果您的所有实体都派生自

      ,这将是可能的
      public interface IEntity { public int Id { get; } }
      

      然后方法会像

      public User GetUser<T, Y>(Func<T, IList<Y>> getlist, Y sample)
         where T: IEntity
         where Y: IEntity
      {
        return db.Users.Select(x => getlist(x).Any(y => y.Id == sample.Id)).FirstOrDefault();
      }
      

      此外,如果我们考虑 S#arp 架构,如果 entity1.Id == entity2.Id(对于持久实体)则 Equals(entity1, entity2) - 我们可以使用 getlist(x).Contains(sample)。

      【讨论】: