Added populate lazy-loading extensions.

This commit is contained in:
kay.one 2013-06-01 23:41:30 -07:00
parent 88cd6a3213
commit b133fa9585
5 changed files with 75 additions and 33 deletions

View File

@ -1,17 +1,22 @@
using System.Collections.Generic;
using NzbDrone.Api.REST;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Tv;
using NzbDrone.Api.Extensions;
using System.Linq;
namespace NzbDrone.Api.Episodes
{
public class EpisodeModule : NzbDroneRestModule<EpisodeResource>
{
private readonly IEpisodeService _episodeService;
private readonly MediaFileRepository _mediaFileRepository;
public EpisodeModule(IEpisodeService episodeService)
public EpisodeModule(IEpisodeService episodeService, MediaFileRepository mediaFileRepository)
: base("/episodes")
{
_episodeService = episodeService;
_mediaFileRepository = mediaFileRepository;
GetResourceAll = GetEpisodes;
}
@ -25,7 +30,10 @@ namespace NzbDrone.Api.Episodes
throw new BadRequestException("seriesId is missing");
}
return ToListResource(() => _episodeService.GetEpisodeBySeries(seriesId.Value));
var resource = ToListResource(() => _episodeService.GetEpisodeBySeries(seriesId.Value))
.LoadSubtype(e => e.EpisodeFileId, _mediaFileRepository);
return resource.ToList();
}
}
}

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NzbDrone.Api.REST;
using NzbDrone.Common.Cache;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Api.Extensions
{
public static class LazyExtensions
{
private static readonly ICached<MethodInfo> SetterCache = new Cached<MethodInfo>();
public static IEnumerable<TParent> LoadSubtype<TParent, TChild>(this IEnumerable<TParent> parents, Func<TParent, int> foreignKeySelector, IBasicRepository<TChild> childRepository)
where TChild : ModelBase, new()
where TParent : RestResource
{
var parentList = parents.Where(p => foreignKeySelector(p) != 0).ToList();
if (!parentList.Any())
{
return parents;
}
var ids = parentList.Select(foreignKeySelector).Distinct();
var childDictionary = childRepository.Get(ids).ToDictionary(child => child.Id, child => child);
var childSetter = GetChildSetter<TParent, TChild>();
foreach (var episode in parentList)
{
childSetter.Invoke(episode, new object[] { childDictionary[foreignKeySelector(episode)] });
}
return parents;
}
private static MethodInfo GetChildSetter<TParent, TChild>()
where TChild : ModelBase
where TParent : RestResource
{
var key = typeof(TChild).FullName + typeof(TParent).FullName;
return SetterCache.Get(key, () =>
{
var property = typeof(TParent).GetProperties().Single(c => c.PropertyType == typeof(TChild));
return property.GetSetMethod();
});
}
}
}

View File

@ -86,6 +86,9 @@
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\NzbDrone.Common\Properties\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Authentication\AuthenticationService.cs" />
<Compile Include="Authentication\EnableBasicAuthInNancy.cs" />
<Compile Include="Authentication\NzbDroneUser.cs" />
@ -111,6 +114,7 @@
<Compile Include="Indexers\IndexerModule.cs" />
<Compile Include="Indexers\IndexerResource.cs" />
<Compile Include="Indexers\ReleaseModule.cs" />
<Compile Include="Extensions\LazyExtensions.cs" />
<Compile Include="Mapping\CloneInjection.cs" />
<Compile Include="Mapping\MappingValidation.cs" />
<Compile Include="Mapping\ResourceMappingException.cs" />

View File

@ -2,36 +2,10 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("NzbDrone.Api")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("NzbDrone.Api")]
[assembly: AssemblyCopyright("Copyright © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4c0922d7-979e-4ff7-b44b-b8ac2100eeb5")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -6,6 +6,7 @@ using Marr.Data;
using Marr.Data.QGen;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Common;
namespace NzbDrone.Core.Datastore
@ -79,12 +80,14 @@ namespace NzbDrone.Core.Datastore
public IEnumerable<TModel> Get(IEnumerable<int> ids)
{
var idList = ids.ToList();
var result = Query.Where(String.Format("Id IN ({0})", String.Join(",", idList))).ToList();
var resultCount = result.Count;
var query = String.Format("Id IN ({0})", String.Join(",", ids));
if (resultCount != idList.Count || result.Select(r => r.Id).Distinct().Count() != resultCount)
throw new InvalidOperationException("Unexpected result from query");
var result = Query.Where(query).ToList();
if (result.Count != ids.Count())
{
throw new ApplicationException("Expected query to return {0} rows but returned {1}".Inject(ids.Count(), result.Count));
}
return result;
}