我如何模仿IQueryable<;T>;.在我的自定义集合中包括(表达式<;函数<;T,TPropert

本文关键字:lt 包括 表达式 函数 集合 TPropert 何模仿 IQueryable gt 我的 自定义 | 更新日期: 2023-09-27 18:00:19

首先,一点背景。我正在使用ASP.NET Web API和Entity Framework 5开发一个REST API,但是系统的要求是在我的ApiControllers和DbContext之间有几个逻辑层。这些逻辑层包括将我的实体从DbContext中分离,将一组假设的更改应用于内存中的实体(我称之为更改集的物化的过程),然后允许用户在应用这些更改时检查系统的新状态。实体的新状态不会立即保存到数据库中。相反,物化保存在web服务器的内存中,用户可以检查当前数据或各种变更集的许多物化中的一个。

现在来谈谈我的问题。

public interface IIdentifiable
{
    long Id { get; set; }
}
public class Foo : IIdentifiable
{
    public long Id { get; set; }
    public string Name { get; set; }
    public List<Bar> Bars { get; set; } // Navigation Property
}
public class Bar : IIdentifiable
{
    public long Id { get; set; }
    public string Name { get; set; }
    public long FooId { get; set; } // Foreign Key Property
    public Foo Foo { get; set; } // Navigation Property
}
public class Materialization
{
    IEnumerable<Foo> Foos { get; set; } 
    IEnumerable<Bar> Bars { get; set; } 
}
public interface IRepository<TItem> : IQueryable<TItem>, ICollection<TItem>, IDisposable
    where TItem : class, IIdentifiable
{
    IRepository<TItem> Include<TProperty>(Expression<Func<TItem, TProperty>> path);
    // Other methods
}
public class MateriailizationRepository<TItem> : IRepository<TItem>
    where TItem : class, IIdentifiable
{
    private Materialization _materialization;
    public MateriailizationRepository(Materialization materialization)
    {
        _materialization = materialization;
    }
    public IRepository<TItem> Include<TProperty>(Expression<Func<TItem, TProperty>> path)
    {
        // Populate navigation property indicated by "path"
    }
    // Other methods
}

每个Bar都有一个外键属性,指示它所属的Foo,但Bar.FooFoo.Bars导航属性没有填充,因为这会使物化过程复杂化。因此,在物化完成后,Materialization.FoosMaterialization.Bars包含通过外键属性而不是通过导航属性相互引用的对象的集合(即,所有导航属性的值都为null或空List<T>s)。我希望能够在我的ApiController中做以下事情。

public IQueryable<Foo> Get (bool includeBars = false)
{
    Materialization materialization;
    // Materialize
    using (IRepository<Foo> repository = new MateriailizationRepository<Foo>(materialization))
    {
        IRepository<Foo> query = repository;
        if (includeBars)
            query = query.Include(f => f.Bars);
        return query;
    }
}

MateriailizationRepository<Foo>的主要职责是获取物化的Foo对象,但由于它引用了整个Materialization,我希望能够根据需要包括来自Materiailization.Bars的物化Bar对象。

如何实现MateriailizationRepository.Include()以模仿IQueryable.Include()扩展方法?

我如何模仿IQueryable<;T>;.在我的自定义集合中包括(表达式<;函数<;T,TPropert

这里有几个选项:

  1. 考虑使用另一个上下文来实现您的MaterializationRepository,并让它由内存中的数据库(如Effort)支持,如果这在今天仍然有效的话
  2. 您自己在物化上重新实现"包含"功能。可以对表达式进行细分以查找导航属性的类型。使用命名约定,您可以计算出需要查询哪些外键属性才能获得正确的标识符。要查找目标存储库,可以使用对Materialization的反射来查找导航属性类型的IEnumerable类型的公共属性。只要知道目标实体的主键的名称(按照约定),就可以使用外键值来查找它

如果您有少量的实体类型,那么最好使用某种switch语句,并手动执行其中的一些操作,而不是通过反射。

很抱歉,这不是一个完整的实施过程,但我希望它能朝着正确的方向发展。