动态访问DbContext

时间:2015-03-07 18:48:04

标签: c# linq entity-framework expression-trees

我有一个用于向用户显示位置数据的应用程序。该数据可以来自多个源(例如WebApi或LocalDatabase)。因此,我有一个存储库来管理来自这些来源的所有数据。 每个存储库都实现以下接口

interface IRepository<TKey, TValue> : IDiscoverable, ILocalizable
{
    IDictionary<TKey, TValue> FindAll();

    TValue Find(TKey identifier);

    // Additional methods left out.
}

具体实现(在本例中为WebApi请求)然后创建一个由ServiceClient执行的请求。此服务客户端向存储库返回响应,该响应将所述响应传递给转换器,该转换器将数据转换为应用程序使用的格式。

现在我的问题是请求部分。不适用于WebApi,而是适用于数据库请求。 我目前有一个用于Locations数据库的DbContext,但是当应用程序扩展时会有更多。这就是关键所在:为Api请求编写ServiceClient很容易,因为我只需要查询网页并获取JSON。因此,可以通过连接多个字符串来构建URL。所以请求看起来像这样:

public interface IRequest
{
    /// <summary>Gets the resource path.</summary>
    string Resource { get; }

    /// <summary>Gets the request parameters.</summary>
    /// <returns>A collection of parameters.</returns>
    IEnumerable<KeyValuePair<string, string>> GetParameters();

    /// <summary>Gets additional path segments for the targeted resource.</summary>
    /// <returns>A collection of path segments.</returns>
    IEnumerable<string> GetPathSegments();
}

如何使用多个DbContext实现类似的方法?

我知道我必须将要查询的DbContext实例传递给服务管理器。但是,如何在不为每个DbContext编写服务管理器的情况下查询DbSet属性?

这是可能的,或者我是否必须完全废弃我的设计?


以下是一些其他信息,这是我当前的存储库实现。我注释掉了用于查询web api的代码。但我希望我的数据库查询代码看起来几乎相同。 澄清一下:显式接口实现是程序其余部分调用获取数据的方法。用户可以切换存储库的类型,从而可以从不同的数据源中进行选择。 在方法内部,我将生成一个请求。如果数据源是web api,则请求保存信息以构建到api端点的URL(由ServiceClient构建和查询Url)。然后ServiceClient返回实现IResponse接口的响应(见下文)。然后将响应传递给转换器,该转换器将响应转换为应用程序其余部分使用的POCO。

我想做什么:构建一个允许我动态选择用于访问数据库的DbContext的请求类。为此,我需要一种方法来传递请求中的DbContext,以便ServiceClient可以使用它。我还需要传递要使用的属性,以便我可以获取数据,因为并非每个端点都具有相同的属性。

这是我有这么胖的代码:

public interface IResponse<T> : ILocalizable
{
    /// <summary>Gets or sets the response content.</summary>
    T Content { get; set; }

    /// <summary>Gets or sets the <see cref="DateTimeOffset"/> at which the message originated..</summary>
    DateTimeOffset Date { get; set; }

    /// <summary>Gets or sets a collection of custom response headers.</summary>
    IDictionary<string, string> ExtensionData { get; set; }
}


public interface ILocationRepository : IRepository<Guid, Location>
{
}

public class LocationRepository : ILocationRepository 
{
    private readonly LocationContext context;

    private readonly IConverter<IResponse<ICollection<LocationDataContract>>, IDictionary<Guid, Location>> responseConverter;


    public LocationRepository()
    {
        this.context = new LocationContext();

        var locationConverter = new LocationConverter();

        this.responseConverter = new DictionaryResponseConverter<LocationDataContract, Guid, Location>(locationConverter, location => location.Id);
    }

    IDictionary<Guid, Location> IRepository<Guid, Location>.FindAll()
    {
        // This is how the request against a web api looks like.
        // This works without a doubt and totally flawless.
        // IItemRepository self = this;
        // var request = new ItemDetailsRequest
        // {
        //     Identifier = identifier.ToString(NumberFormatInfo.InvariantInfo), 
        //     Culture = self.Culture
        // };
        // var response = this.serviceClient.Send<ItemDataContract>(request);

        var locations = this.context.Locations.ToList();
        var cityDetails = this.context.CityDetails.ToList();
        var planetDetails = this.context.PlanetDetails.ToList();
        var systemDetails = this.context.SystemDetails.ToList();


        IEnumerable<LocationsDetails> details = cityDetails.Cast<LocationsDetails>().Concat(planetDetails).Concat(systemDetails).ToList();

        foreach (var location in locations)
        {
            location.Details = details.SingleOrDefault(detail => detail.Id == location.Id);
        }

        var response = new Response<ICollection<LocationDataContract>>
                           {
                               Content = locations
                           };

        var service = new DatabaseServiceClient<LocationContext>();

        return this.responseConverter.Convert(response);
    }

    Location IRepository<Guid, Location>.Find(Guid identifier)
    {
        throw new NotImplementedException();
    }
}

0 个答案:

没有答案