[Uno] KeyEquality
.NET 단일 코드로 크로스플랫폼 앱을 만들 수 있는 Uno Platform에서는 동일한 엔터티임을 비교하는 KeyEquality를 지원합니다. 사용방법은 다음과 같습니다.
public partial record Entity(string Id, ...)
속성명 Id
는 암시적으로 키로 인식하며 다음 처럼 KeyEquals()
로 키 동등을 비교할 수 있습니다.
entity.KeyEquals(...);
키 동등은 키 이외의 값이 다르더라도 동일한 엔터티라고 판단한다는 점에서 record
의 Equals
와는 다르게 동작합니다.
public partial record Person([property: Key] string Name, int Age);
var john1 = new Person("John Doe", 20);
var john2 = john1 with { Age=21 };
Console.WriteLine("Are the same : " + john1.Equals(john2));
Console.WriteLine("Are the same person : " + john1.KeyEquals(john2));
Equals()
는 false
이지만 KeyEquals()
의 결과는 true
가 됩니다.
Are the same : false
Are the same person : true
그렇다면 왜 KeyEquals()
가 필요할까요? record
로 정의된 엔터티는 엔터티의 모든 값에 대한 동등성을 평가하기 보다는 키를 기준으로 동등함과 변경됨을 판단하는 것이 유용합니다. 예를 들어 데이터베이스의 레코드를 업데이트 하는 경우가 되겠습니다.
Uno Platform에서는 이러한 키 동등성을 소스 생성기를 이용해서 자동으로 생성합니다.
partial record Person : global::Uno.Extensions.Equality.IKeyEquatable<BibleVerseCounter.Business.Models.Person>, global::Uno.Extensions.Equality.IKeyed<string>
{
/// <inheritdoc cref="{NS.Equality}.IKeyed{T}" />
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("KeyEqualityGenerationTool", "1")]
string global::Uno.Extensions.Equality.IKeyed<string>.Key
{
get
{
return Name;
}
}
/// <inheritdoc cref="global::Uno.Extensions.Equality.IKeyEquatable{T}" />
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("KeyEqualityGenerationTool", "1")]
public virtual int GetKeyHashCode()
{
unchecked
{
var hash = global::System.Collections.Generic.EqualityComparer<global::System.Type>.Default.GetHashCode(EqualityContract) * -1521134295;
hash += global::System.Collections.Generic.EqualityComparer<string>.Default.GetHashCode(Name);
hash *= -1521134295;
return hash;
}
}
/// <inheritdoc cref="global::Uno.Extensions.Equality.IKeyEquatable{T}" />
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("KeyEqualityGenerationTool", "1")]
public bool KeyEquals(BibleVerseCounter.Business.Models.Person? other)
{
if (object.ReferenceEquals(this, other))
{
return true;
}
if (object.ReferenceEquals(null, other)
|| EqualityContract != other.EqualityContract)
{
return false;
}
return global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(Name, other.Name);
}
}
자동 생성된 코드를 보면 IKeyEquatable<>
인터페이스와 IKeyed<string>
인터페이스가 구현 된 것을 볼 수 있습니다.
복합 키를 정의할 수도 있는데 사용 방법은 간단합니다. [property:Key]
특성을 키 속성에 다음처럼 복수로 장식하면,
public partial record CompositeKeyEntity(
[property:Key] string Key1,
[property:Key] string Key2,
string Value1
);
다음처럼 Uno의 자동 생성 기능으로 코드가 생성 됩니다.
partial record CompositeKeyEntity : global::Uno.Extensions.Equality.IKeyEquatable<BibleVerseCounter.Business.Models.CompositeKeyEntity>, global::Uno.Extensions.Equality.IKeyed<(string, string)>
{
/// <inheritdoc cref="{NS.Equality}.IKeyed{T}" />
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("KeyEqualityGenerationTool", "1")]
(string, string) global::Uno.Extensions.Equality.IKeyed<(string, string)>.Key
{
get
{
return (Key1, Key2);
}
}
/// <inheritdoc cref="global::Uno.Extensions.Equality.IKeyEquatable{T}" />
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("KeyEqualityGenerationTool", "1")]
public virtual int GetKeyHashCode()
{
unchecked
{
var hash = global::System.Collections.Generic.EqualityComparer<global::System.Type>.Default.GetHashCode(EqualityContract) * -1521134295;
hash += global::System.Collections.Generic.EqualityComparer<string>.Default.GetHashCode(Key1);
hash *= -1521134295;
hash += global::System.Collections.Generic.EqualityComparer<string>.Default.GetHashCode(Key2);
hash *= -1521134295;
return hash;
}
}
/// <inheritdoc cref="global::Uno.Extensions.Equality.IKeyEquatable{T}" />
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("KeyEqualityGenerationTool", "1")]
public bool KeyEquals(BibleVerseCounter.Business.Models.CompositeKeyEntity? other)
{
if (object.ReferenceEquals(this, other))
{
return true;
}
if (object.ReferenceEquals(null, other)
|| EqualityContract != other.EqualityContract)
{
return false;
}
return global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(Key1, other.Key1)
&& global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(Key2, other.Key2);
}
}