LinkIt 2.0.0
dotnet add package LinkIt --version 2.0.0
NuGet\Install-Package LinkIt -Version 2.0.0
<PackageReference Include="LinkIt" Version="2.0.0" />
paket add LinkIt --version 2.0.0
#r "nuget: LinkIt, 2.0.0"
// Install LinkIt as a Cake Addin
#addin nuget:?package=LinkIt&version=2.0.0
// Install LinkIt as a Cake Tool
#tool nuget:?package=LinkIt&version=2.0.0
Getting Started
To execute this example, see LinkIt.Samples.
Linked Source
A linked source is a class that has a property called Model
, and other properties called link targets. For example, let's say you have these two classes that you fetched separately by IDs.
public class Media {
public int Id { get; set; }
public string Title { get; set; }
public List<int> TagIds { get; set; } //Tag references
}
public class Tag {
public int Id { get; set; }
public string Name { get; set; }
}
The linked source representing a media with its tags would be a class like this.
public class MediaLinkedSource : ILinkedSource<Media> {
public Media Model { get; set; }
public List<Tag> Tags { get; set; }
}
Usage
Load link by ID
var actual = _loadLinkProtocol.LoadLink<MediaLinkedSource>().ById(1);
Load link by IDs
var actual = _loadLinkProtocol.LoadLink<MediaLinkedSource>().ByIds(
new List<int>{1, 2, 3}
);
However, prior to being able to use _loadLinkProtocol.LoadLink
, you need to define a reference loader and a load link protocol.
ReferenceLoader
LinkIt can load objects spread across many data sources (web services, SQL databases, NoSQL databases, in-memory caches, file systems, Git repositories, etc.) and link them together as long as those objects can be fetched by IDs. LinkIt is not responsible for defining how the objects are loaded, you must define this process for each possible reference type in a reference loader.
Here is a reference loader that loads fake data for our example.
public class FakeReferenceLoader:IReferenceLoader
{
public void LoadReferences(LookupIdContext lookupIdContext, LoadedReferenceContext loadedReferenceContext){
foreach (var referenceType in lookupIdContext.GetReferenceTypes()){
LoadReference(referenceType, lookupIdContext, loadedReferenceContext);
}
}
private void LoadReference(Type referenceType, ILookupIdContext lookupIdContext, ILoadedReferenceContext loadedReferenceContext)
{
if (referenceType == typeof(Media)) {
LoadMedia(lookupIdContext, loadedReferenceContext);
}
if (referenceType == typeof(Tag)){
LoadTags(lookupIdContext, loadedReferenceContext);
}
}
private void LoadMedia(ILookupIdContext lookupIdContext, ILoadedReferenceContext loadedReferenceContext) {
var lookupIds = lookupIdContext.GetReferenceIds<Media, int>();
var references = lookupIds
.Select(id =>
new Media{
Id = id,
Title = "title-" + id,
TagIds = new List<int> {
1000+id,
1001+id
}
}
)
.ToList();
loadedReferenceContext.AddReferences(
references,
reference => reference.Id
);
}
private void LoadTags(ILookupIdContext lookupIdContext, ILoadedReferenceContext loadedReferenceContext){
var lookupIds = lookupIdContext.GetReferenceIds<Tag, int>();
var references = lookupIds
.Select(id=>
new Tag {
Id = id,
Name = id+"-name"
}
)
.ToList();
loadedReferenceContext.AddReferences(
references,
reference => reference.Id
);
}
public void Dispose(){
//In case you need to dispose database connections or other resources.
//Will always be invoked as soon as the load phase is completed or
//if an exception is thrown
}
}
ReferenceLoader and the Select N + 1 Problem
LinkIt will always provide all lookup IDs for a reference type in one batch; avoiding the select N + 1 problem.
For example, if we load link the MediaLinkedSource
for IDs "one"
and "two"
, and the state of those media is
[
{
"id":"one",
"title":"title-one",
"tagIds":[1,2]
},
{
"id":"two",
"title":"title-two",
"tagIds":[2,3]
}
]
the lookup IDs for Tag
would then be 1,2,3
.
Note that lookup IDs are always provided without duplicates and without null IDs. Moreover, all the lookup IDs for the same reference type will always be loaded in one batch regardless of the complexity of the linked sources.
LoadLinkProtocol
A load link protocol has to be defined in order to load and link a linked source. Here is the protocol configuration for MediaLinkedSource
.
public class MediaLinkedSourceConfig : ILoadLinkProtocolConfig {
public void ConfigureLoadLinkProtocol(LoadLinkProtocolBuilder loadLinkProtocolBuilder) {
loadLinkProtocolBuilder.For<MediaLinkedSource>()
.LoadLinkReferenceById(
linkedSource => linkedSource.Model.TagIds,
linkedSource => linkedSource.Tags
);
}
}
However, we favor convention over configuration.
By default, the load link protocol is defined by convention
- when a model property name with the suffix
Id
orIds
matches a link target name - when a model property name is the same as a link target name
Since the model property Model.TagIds
match the link target Tags
, the MediaLinkedSourceConfig
defined above is unnecessary and can be omitted.
When invoking loadLinkProtocolBuilder.Build
, all the assemblies passed by argument will be scanned in order to apply the conventions and the configuration classes implementing ILoadLinkProtocolConfig
. If a convention conflicts with a configuration explicitly defined in a ILoadLinkProtocolConfig
, the configuration defined in a ILoadLinkProtocolConfig
wins.
var loadLinkProtocolBuilder = new LoadLinkProtocolBuilder();
_loadLinkProtocol = loadLinkProtocolBuilder.Build(
()=>new FakeReferenceLoader(),
new[] { Assembly.GetExecutingAssembly() },
LoadLinkExpressionConvention.Default
);
To create your own conventions, please see how the existing conventions are built. Then, simply pass your convention by argument when calling loadLinkProtocolBuilder.Build
.
Read more
See also
- Perform complex projections easily with LinkIt AutoMapper Extensions
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net45 is compatible. net451 was computed. net452 was computed. net46 was computed. net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.5
- No dependencies.
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.0.0 | 10,881 | 5/9/2019 |
2.0.0-rc07 | 570 | 11/8/2018 |
2.0.0-rc06 | 587 | 10/25/2018 |
2.0.0-rc03 | 738 | 6/15/2018 |
2.0.0-rc01 | 851 | 3/14/2018 |
2.0.0-beta4 | 806 | 3/1/2018 |
1.1.0 | 1,147 | 1/9/2018 |
1.0.2 | 1,879 | 11/2/2016 |