Removing most of the things needed for a custom many to many

This commit is contained in:
Zoe Roux 2021-03-01 00:49:03 +01:00
parent b2b53f2691
commit fef6a93a1d
22 changed files with 70 additions and 432 deletions

View File

@ -239,6 +239,23 @@ namespace Kyoo
return types.FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == genericType);
}
public static async IAsyncEnumerable<T2> SelectAsync<T, T2>(this IEnumerable<T> self, Func<T, Task<T2>> mapper)
{
using IEnumerator<T> enumerator = self.GetEnumerator();
while (enumerator.MoveNext())
yield return await mapper(enumerator.Current);
}
public static async Task<List<T>> ToListAsync<T>(this IAsyncEnumerable<T> self)
{
List<T> ret = new();
await foreach(T i in self)
ret.Add(i);
return ret;
}
public static IEnumerable<T> IfEmpty<T>(this IEnumerable<T> self, Action action)
{
using IEnumerator<T> enumerator = self.GetEnumerator();

View File

@ -15,7 +15,7 @@ using Microsoft.EntityFrameworkCore.Metadata;
namespace Kyoo.Controllers
{
public abstract class LocalRepository<T>
public abstract class LocalRepository<T> : IRepository<T>
where T : class, IResource
{
protected readonly DbContext Database;
@ -53,6 +53,8 @@ namespace Kyoo.Controllers
return Database.Set<T>().FirstOrDefaultAsync(predicate);
}
public abstract Task<ICollection<T>> Search(string query);
public virtual Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
Sort<T> sort = default,
Pagination limit = default)
@ -256,112 +258,4 @@ namespace Kyoo.Controllers
await Delete(slug);
}
}
public abstract class LocalRepository<T, TInternal> : LocalRepository<TInternal>, IRepository<T>
where T : class, IResource
where TInternal : class, T, new()
{
protected LocalRepository(DbContext database) : base(database) { }
public new Task<T> Get(int id)
{
return base.Get(id).Cast<T>();
}
public new Task<T> Get(string slug)
{
return base.Get(slug).Cast<T>();
}
public Task<T> Get(Expression<Func<T, bool>> predicate)
{
return Get(predicate.Convert<Func<TInternal, bool>>()).Cast<T>();
}
public abstract Task<ICollection<T>> Search(string query);
public virtual Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
Sort<T> sort = default,
Pagination limit = default)
{
return ApplyFilters(Database.Set<TInternal>(), where, sort, limit);
}
protected virtual async Task<ICollection<T>> ApplyFilters(IQueryable<TInternal> query,
Expression<Func<T, bool>> where = null,
Sort<T> sort = default,
Pagination limit = default)
{
ICollection<TInternal> items = await ApplyFilters(query,
base.Get,
DefaultSort,
where.Convert<Func<TInternal, bool>>(),
sort.To<TInternal>(),
limit);
return items.ToList<T>();
}
public virtual Task<int> GetCount(Expression<Func<T, bool>> where = null)
{
IQueryable<TInternal> query = Database.Set<TInternal>();
if (where != null)
query = query.Where(where.Convert<Func<TInternal, bool>>());
return query.CountAsync();
}
Task<T> IRepository<T>.Create(T item)
{
if (item == null)
throw new ArgumentNullException(nameof(item));
TInternal obj = item as TInternal ?? new TInternal();
if (!(item is TInternal))
Utility.Assign(obj, item);
return Create(obj).Cast<T>()
.Then(x => item.ID = x.ID);
}
Task<T> IRepository<T>.CreateIfNotExists(T item, bool silentFail)
{
if (item == null)
throw new ArgumentNullException(nameof(item));
TInternal obj = item as TInternal ?? new TInternal();
if (!(item is TInternal))
Utility.Assign(obj, item);
return CreateIfNotExists(obj, silentFail).Cast<T>()
.Then(x => item.ID = x.ID);
}
public Task<T> Edit(T edited, bool resetOld)
{
if (edited == null)
throw new ArgumentNullException(nameof(edited));
if (edited is TInternal intern)
return Edit(intern, resetOld).Cast<T>();
TInternal obj = new();
Utility.Assign(obj, edited);
return base.Edit(obj, resetOld).Cast<T>();
}
public abstract override Task Delete([NotNull] TInternal obj);
Task IRepository<T>.Delete(T obj)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
if (obj is TInternal intern)
return Delete(intern);
TInternal item = new();
Utility.Assign(item, obj);
return Delete(item);
}
public virtual async Task DeleteRange(IEnumerable<T> objs)
{
foreach (T obj in objs)
await ((IRepository<T>)this).Delete(obj);
}
}
}

View File

@ -8,11 +8,11 @@ using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
{
public class CollectionRepository : LocalRepository<Collection, CollectionDE>, ICollectionRepository
public class CollectionRepository : LocalRepository<Collection>, ICollectionRepository
{
private bool _disposed;
private readonly DatabaseContext _database;
protected override Expression<Func<CollectionDE, object>> DefaultSort => x => x.Name;
protected override Expression<Func<Collection, object>> DefaultSort => x => x.Name;
public CollectionRepository(DatabaseContext database) : base(database)
{
@ -40,10 +40,10 @@ namespace Kyoo.Controllers
return await _database.Collections
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
.Take(20)
.ToListAsync<Collection>();
.ToListAsync();
}
public override async Task<CollectionDE> Create(CollectionDE obj)
public override async Task<Collection> Create(Collection obj)
{
await base.Create(obj);
_database.Entry(obj).State = EntityState.Added;
@ -51,18 +51,12 @@ namespace Kyoo.Controllers
return obj;
}
public override async Task Delete(CollectionDE obj)
public override async Task Delete(Collection obj)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
_database.Entry(obj).State = EntityState.Deleted;
if (obj.Links != null)
foreach (CollectionLink link in obj.Links)
_database.Entry(link).State = EntityState.Deleted;
if (obj.LibraryLinks != null)
foreach (LibraryLink link in obj.LibraryLinks)
_database.Entry(link).State = EntityState.Deleted;
await _database.SaveChangesAsync();
}
}

View File

@ -86,7 +86,7 @@ namespace Kyoo.Controllers
&& x.AbsoluteNumber == absoluteNumber);
}
public async Task<ICollection<Episode>> Search(string query)
public override async Task<ICollection<Episode>> Search(string query)
{
return await _database.Episodes
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))

View File

@ -8,11 +8,11 @@ using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
{
public class GenreRepository : LocalRepository<Genre, GenreDE>, IGenreRepository
public class GenreRepository : LocalRepository<Genre>, IGenreRepository
{
private bool _disposed;
private readonly DatabaseContext _database;
protected override Expression<Func<GenreDE, object>> DefaultSort => x => x.Slug;
protected override Expression<Func<Genre, object>> DefaultSort => x => x.Slug;
public GenreRepository(DatabaseContext database) : base(database)
@ -41,10 +41,10 @@ namespace Kyoo.Controllers
return await _database.Genres
.Where(genre => EF.Functions.ILike(genre.Name, $"%{query}%"))
.Take(20)
.ToListAsync<Genre>();
.ToListAsync();
}
public override async Task<GenreDE> Create(GenreDE obj)
public override async Task<Genre> Create(Genre obj)
{
await base.Create(obj);
_database.Entry(obj).State = EntityState.Added;
@ -52,15 +52,12 @@ namespace Kyoo.Controllers
return obj;
}
public override async Task Delete(GenreDE obj)
public override async Task Delete(Genre obj)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
_database.Entry(obj).State = EntityState.Deleted;
if (obj.Links != null)
foreach (GenreLink link in obj.Links)
_database.Entry(link).State = EntityState.Deleted;
await _database.SaveChangesAsync();
}
}

View File

@ -71,7 +71,7 @@ namespace Kyoo.Controllers
private IQueryable<LibraryItem> ItemsQuery
=> _database.Shows
// .Where(x => !_database.CollectionLinks.Any(y => y.ChildID == x.ID))
.Where(x => !_database.CollectionLinks.Any(y => y.ChildID == x.ID))
.Select(LibraryItem.FromShow)
.Concat(_database.Collections
.Select(LibraryItem.FromCollection));
@ -114,18 +114,17 @@ namespace Kyoo.Controllers
public override Task Delete(LibraryItem obj) => throw new InvalidOperationException();
private IQueryable<LibraryItem> LibraryRelatedQuery(Expression<Func<LibraryLink, bool>> selector)
=> throw new NotImplementedException();
// => _database.LibraryLinks
// .Where(selector)
// .Select(x => x.Show)
// .Where(x => x != null)
// .Where(x => !_database.CollectionLinks.Any(y => y.ChildID == x.ID))
// .Select(LibraryItem.FromShow)
// .Concat(_database.LibraryLinks
// .Where(selector)
// .Select(x => x.Collection)
// .Where(x => x != null)
// .Select(LibraryItem.FromCollection));
=> _database.LibraryLinks
.Where(selector)
.Select(x => x.Show)
.Where(x => x != null)
.Where(x => !_database.CollectionLinks.Any(y => y.ChildID == x.ID))
.Select(LibraryItem.FromShow)
.Concat(_database.LibraryLinks
.Where(selector)
.Select(x => x.Collection)
.Where(x => x != null)
.Select(LibraryItem.FromCollection));
public async Task<ICollection<LibraryItem>> GetFromLibrary(int id,
Expression<Func<LibraryItem, bool>> where = null,

View File

@ -10,12 +10,12 @@ using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Controllers
{
public class LibraryRepository : LocalRepository<Library, LibraryDE>, ILibraryRepository
public class LibraryRepository : LocalRepository<Library>, ILibraryRepository
{
private bool _disposed;
private readonly DatabaseContext _database;
private readonly IProviderRepository _providers;
protected override Expression<Func<LibraryDE, object>> DefaultSort => x => x.ID;
protected override Expression<Func<Library, object>> DefaultSort => x => x.ID;
public LibraryRepository(DatabaseContext database, IProviderRepository providers)
@ -48,22 +48,18 @@ namespace Kyoo.Controllers
return await _database.Libraries
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
.Take(20)
.ToListAsync<Library>();
.ToListAsync();
}
public override async Task<LibraryDE> Create(LibraryDE obj)
public override async Task<Library> Create(Library obj)
{
await base.Create(obj);
_database.Entry(obj).State = EntityState.Added;
if (obj.ProviderLinks != null)
foreach (ProviderLink entry in obj.ProviderLinks)
_database.Entry(entry).State = EntityState.Added;
await _database.SaveChangesAsync($"Trying to insert a duplicated library (slug {obj.Slug} already exists).");
return obj;
}
protected override async Task Validate(LibraryDE resource)
protected override async Task Validate(Library resource)
{
if (string.IsNullOrEmpty(resource.Slug))
throw new ArgumentException("The library's slug must be set and not empty");
@ -74,24 +70,17 @@ namespace Kyoo.Controllers
await base.Validate(resource);
if (resource.ProviderLinks != null)
foreach (ProviderLink link in resource.ProviderLinks)
if (ShouldValidate(link))
link.Child = await _providers.CreateIfNotExists(link.Child, true);
resource.Providers = await resource.Providers
.SelectAsync(x => _providers.CreateIfNotExists(x, true))
.ToListAsync();
}
public override async Task Delete(LibraryDE obj)
public override async Task Delete(Library obj)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
_database.Entry(obj).State = EntityState.Deleted;
if (obj.ProviderLinks != null)
foreach (ProviderLink entry in obj.ProviderLinks)
_database.Entry(entry).State = EntityState.Deleted;
if (obj.Links != null)
foreach (LibraryLink entry in obj.Links)
_database.Entry(entry).State = EntityState.Deleted;
await _database.SaveChangesAsync();
}
}

View File

@ -49,7 +49,7 @@ namespace Kyoo.Controllers
await _shows.Value.DisposeAsync();
}
public async Task<ICollection<People>> Search(string query)
public override async Task<ICollection<People>> Search(string query)
{
return await _database.People
.Where(people => EF.Functions.ILike(people.Name, $"%{query}%"))

View File

@ -19,7 +19,7 @@ namespace Kyoo.Controllers
_database = database;
}
public async Task<ICollection<ProviderID>> Search(string query)
public override async Task<ICollection<ProviderID>> Search(string query)
{
return await _database.Providers
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))

View File

@ -74,7 +74,7 @@ namespace Kyoo.Controllers
&& x.SeasonNumber == seasonNumber);
}
public async Task<ICollection<Season>> Search(string query)
public override async Task<ICollection<Season>> Search(string query)
{
return await _database.Seasons
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))

View File

@ -9,7 +9,7 @@ using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Controllers
{
public class ShowRepository : LocalRepository<Show, ShowDE>, IShowRepository
public class ShowRepository : LocalRepository<Show>, IShowRepository
{
private bool _disposed;
private readonly DatabaseContext _database;
@ -19,7 +19,7 @@ namespace Kyoo.Controllers
private readonly IProviderRepository _providers;
private readonly Lazy<ISeasonRepository> _seasons;
private readonly Lazy<IEpisodeRepository> _episodes;
protected override Expression<Func<ShowDE, object>> DefaultSort => x => x.Title;
protected override Expression<Func<Show, object>> DefaultSort => x => x.Title;
public ShowRepository(DatabaseContext database,
IStudioRepository studios,
@ -81,21 +81,11 @@ namespace Kyoo.Controllers
.ToListAsync<Show>();
}
public override async Task<ShowDE> Create(ShowDE obj)
public override async Task<Show> Create(Show obj)
{
await base.Create(obj);
_database.Entry(obj).State = EntityState.Added;
if (obj.GenreLinks != null)
{
foreach (GenreLink entry in obj.GenreLinks)
{
if (!(entry.Child is GenreDE))
entry.Child = new GenreDE(entry.Child);
_database.Entry(entry).State = EntityState.Added;
}
}
if (obj.People != null)
foreach (PeopleRole entry in obj.People)
_database.Entry(entry).State = EntityState.Added;
@ -107,17 +97,16 @@ namespace Kyoo.Controllers
return obj;
}
protected override async Task Validate(ShowDE resource)
protected override async Task Validate(Show resource)
{
await base.Validate(resource);
if (ShouldValidate(resource.Studio))
resource.Studio = await _studios.CreateIfNotExists(resource.Studio, true);
if (resource.GenreLinks != null)
foreach (GenreLink link in resource.GenreLinks)
if (ShouldValidate(link))
link.Child = await _genres.CreateIfNotExists(link.Child, true);
resource.Genres = await resource.Genres
.SelectAsync(x => _genres.CreateIfNotExists(x, true))
.ToListAsync();
if (resource.People != null)
foreach (PeopleRole link in resource.People)
@ -134,32 +123,30 @@ namespace Kyoo.Controllers
{
if (collectionID != null)
{
// await _database.CollectionLinks.AddAsync(new CollectionLink {ParentID = collectionID.Value, ChildID = showID});
await _database.CollectionLinks.AddAsync(new CollectionLink {ParentID = collectionID.Value, ChildID = showID});
await _database.SaveIfNoDuplicates();
}
if (libraryID != null)
{
// await _database.LibraryLinks.AddAsync(new LibraryLink {LibraryID = libraryID.Value, ShowID = showID});
await _database.LibraryLinks.AddAsync(new LibraryLink {LibraryID = libraryID.Value, ShowID = showID});
await _database.SaveIfNoDuplicates();
}
if (libraryID != null && collectionID != null)
{
// await _database.LibraryLinks.AddAsync(new LibraryLink {LibraryID = libraryID.Value, CollectionID = collectionID.Value});
await _database.LibraryLinks.AddAsync(new LibraryLink {LibraryID = libraryID.Value, CollectionID = collectionID.Value});
await _database.SaveIfNoDuplicates();
}
}
public override async Task Delete(ShowDE obj)
public override async Task Delete(Show obj)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
_database.Entry(obj).State = EntityState.Deleted;
if (obj.GenreLinks != null)
foreach (GenreLink entry in obj.GenreLinks)
_database.Entry(entry).State = EntityState.Deleted;
if (obj.People != null)
foreach (PeopleRole entry in obj.People)
@ -169,14 +156,6 @@ namespace Kyoo.Controllers
foreach (MetadataID entry in obj.ExternalIDs)
_database.Entry(entry).State = EntityState.Deleted;
if (obj.CollectionLinks != null)
foreach (CollectionLink entry in obj.CollectionLinks)
_database.Entry(entry).State = EntityState.Deleted;
if (obj.LibraryLinks != null)
foreach (LibraryLink entry in obj.LibraryLinks)
_database.Entry(entry).State = EntityState.Deleted;
await _database.SaveChangesAsync();
if (obj.Seasons != null)

View File

@ -19,7 +19,7 @@ namespace Kyoo.Controllers
_database = database;
}
public async Task<ICollection<Studio>> Search(string query)
public override async Task<ICollection<Studio>> Search(string query)
{
return await _database.Studios
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))

View File

@ -73,7 +73,7 @@ namespace Kyoo.Controllers
&& x.IsForced == forced);
}
public Task<ICollection<Track>> Search(string query)
public override Task<ICollection<Track>> Search(string query)
{
throw new InvalidOperationException("Tracks do not support the search method.");
}

View File

@ -119,12 +119,6 @@ namespace Kyoo
modelBuilder.Entity<Episode>()
.HasIndex(x => new {x.ShowID, x.SeasonNumber, x.EpisodeNumber, x.AbsoluteNumber})
.IsUnique();
modelBuilder.Entity<LibraryLink>()
.HasIndex(x => new {x.LibraryID, x.ShowID})
.IsUnique();
modelBuilder.Entity<LibraryLink>()
.HasIndex(x => new {x.LibraryID, x.CollectionID})
.IsUnique();
}
public override int SaveChanges()

View File

@ -1,20 +0,0 @@
namespace Kyoo.Models
{
public class CollectionLink : IResourceLink<Collection, Show>
{
public int ParentID { get; set; }
public virtual Collection Parent { get; set; }
public int ChildID { get; set; }
public virtual Show Child { get; set; }
public CollectionLink() { }
public CollectionLink(Collection parent, Show child)
{
Parent = parent;
ParentID = parent.ID;
Child = child;
ChildID = child.ID;
}
}
}

View File

@ -1,18 +0,0 @@
namespace Kyoo.Models
{
public class GenreLink : IResourceLink<Show, Genre>
{
public int ParentID { get; set; }
public virtual Show Parent { get; set; }
public int ChildID { get; set; }
public virtual Genre Child { get; set; }
public GenreLink() {}
public GenreLink(Show parent, Genre child)
{
Parent = parent;
Child = child;
}
}
}

View File

@ -1,27 +0,0 @@
namespace Kyoo.Models
{
public class LibraryLink
{
public int ID { get; set; }
public int LibraryID { get; set; }
public virtual Library Library { get; set; }
public int? ShowID { get; set; }
public virtual Show Show { get; set; }
public int? CollectionID { get; set; }
public virtual Collection Collection { get; set; }
public LibraryLink() { }
public LibraryLink(Library library, Show show)
{
Library = library;
Show = show;
}
public LibraryLink(Library library, Collection collection)
{
Library = library;
Collection = collection;
}
}
}

View File

@ -1,20 +0,0 @@
using Newtonsoft.Json;
namespace Kyoo.Models
{
public class ProviderLink : IResourceLink<Library, ProviderID>
{
[JsonIgnore] public int ParentID { get; set; }
[JsonIgnore] public virtual Library Parent { get; set; }
[JsonIgnore] public int ChildID { get; set; }
[JsonIgnore] public virtual ProviderID Child { get; set; }
public ProviderLink() { }
public ProviderLink(ProviderID child, Library parent)
{
Child = child;
Parent = parent;
}
}
}

View File

@ -1,33 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Kyoo.Models.Attributes;
namespace Kyoo.Models
{
public class CollectionDE : Collection
{
[SerializeIgnore] [NotMergable] public virtual ICollection<CollectionLink> Links { get; set; }
[ExpressionRewrite(nameof(Links), nameof(CollectionLink.Child))]
public override ICollection<Show> Shows
{
get => Links?.Select(x => x.Child).ToList();
set => Links = value?.Select(x => new CollectionLink(this, x)).ToList();
}
[SerializeIgnore] [NotMergable] public virtual ICollection<LibraryLink> LibraryLinks { get; set; }
[ExpressionRewrite(nameof(LibraryLinks), nameof(GenreLink.Child))]
public override ICollection<Library> Libraries
{
get => LibraryLinks?.Select(x => x.Library).ToList();
set => LibraryLinks = value?.Select(x => new LibraryLink(x, this)).ToList();
}
public CollectionDE() {}
public CollectionDE(Collection collection)
{
Utility.Assign(this, collection);
}
}
}

View File

@ -1,25 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Kyoo.Models.Attributes;
namespace Kyoo.Models
{
public class GenreDE : Genre
{
[SerializeIgnore] [NotMergable] public virtual ICollection<GenreLink> Links { get; set; }
[ExpressionRewrite(nameof(Links), nameof(GenreLink.Child))]
[SerializeIgnore] [NotMergable] public override ICollection<Show> Shows
{
get => Links?.Select(x => x.Parent).ToList();
set => Links = value?.Select(x => new GenreLink(x, this)).ToList();
}
public GenreDE() {}
public GenreDE(Genre item)
{
Utility.Assign(this, item);
}
}
}

View File

@ -1,42 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Kyoo.Models.Attributes;
namespace Kyoo.Models
{
public class LibraryDE : Library
{
[EditableRelation] [SerializeIgnore] [NotMergable] public virtual ICollection<ProviderLink> ProviderLinks { get; set; }
[ExpressionRewrite(nameof(ProviderLinks), nameof(ProviderLink.Child))]
public override ICollection<ProviderID> Providers
{
get => ProviderLinks?.Select(x => x.Child).ToList();
set => ProviderLinks = value?.Select(x => new ProviderLink(x, this)).ToList();
}
[SerializeIgnore] [NotMergable] public virtual ICollection<LibraryLink> Links { get; set; }
[ExpressionRewrite(nameof(Links), nameof(LibraryLink.Show))]
public override ICollection<Show> Shows
{
get => Links?.Where(x => x.Show != null).Select(x => x.Show).ToList();
set => Links = Utility.MergeLists(
value?.Select(x => new LibraryLink(this, x)),
Links?.Where(x => x.Show == null))?.ToList();
}
[ExpressionRewrite(nameof(Links), nameof(LibraryLink.Collection))]
public override ICollection<Collection> Collections
{
get => Links?.Where(x => x.Collection != null).Select(x => x.Collection).ToList();
set => Links = Utility.MergeLists(
value?.Select(x => new LibraryLink(this, x)),
Links?.Where(x => x.Collection == null))?.ToList();
}
public LibraryDE() {}
public LibraryDE(Library item)
{
Utility.Assign(this, item);
}
}
}

View File

@ -1,40 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Kyoo.Models.Attributes;
namespace Kyoo.Models
{
public class ShowDE : Show
{
[EditableRelation] [SerializeIgnore] [NotMergable] public virtual ICollection<GenreLink> GenreLinks { get; set; }
[ExpressionRewrite(nameof(GenreLinks), nameof(GenreLink.Child))]
public override ICollection<Genre> Genres
{
get => GenreLinks?.Select(x => x.Child).ToList();
set => GenreLinks = value?.Select(x => new GenreLink(this, x)).ToList();
}
[SerializeIgnore] [NotMergable] public virtual ICollection<LibraryLink> LibraryLinks { get; set; }
[ExpressionRewrite(nameof(LibraryLinks), nameof(LibraryLink.Library))]
public override ICollection<Library> Libraries
{
get => LibraryLinks?.Select(x => x.Library).ToList();
set => LibraryLinks = value?.Select(x => new LibraryLink(x, this)).ToList();
}
[SerializeIgnore] [NotMergable] public virtual ICollection<CollectionLink> CollectionLinks { get; set; }
[ExpressionRewrite(nameof(CollectionLinks), nameof(CollectionLink.Parent))]
public override ICollection<Collection> Collections
{
get => CollectionLinks?.Select(x => x.Parent).ToList();
set => CollectionLinks = value?.Select(x => new CollectionLink(x, this)).ToList();
}
public ShowDE() {}
public ShowDE(Show show)
{
Utility.Assign(this, show);
}
}
}