我有一个用于向用户显示位置数据的应用程序。该数据可以来自多个源(例如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();
}
}