4

首先,一点背景。我正在使用 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.Foos包含Materialization.Bars通过外键属性而不是导航属性相互引用的对象集合(即所有导航属性的值都是 null 或空List<T>)。我希望能够在我的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我希望能够按需包含物化Bar对象。Materiailization.Bars

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

4

1 回答 1

0

这里有几个选项:

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

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

很抱歉,这不是一个完全有效的实施,但我希望它朝着正确的方向发展。

于 2014-02-12T14:49:28.617 回答