I have these 3 Value Object (LanguageId, AttributeSetId and AttributeSetTranslationId
public record LanguageId(string LangCode);
public record AttributeSetId(Guid Value);
public record AttributeSetTranslationId(AttributeSetId AttributeSetId, LanguageId LanguageId);
public sealed class AttributeSet
{
private readonly List<AttributeSetTranslation> _attributeSetTranslations = new();
public AttributeSetId Id { get; private set; }
public IReadOnlyCollection<AttributeSetTranslation> AttributeSetTranslations => _attributeSetTranslations.ToList();
}
public class AttributeSetTranslation
{
public AttributeSetTranslationId Id { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
}
As you can see, the Value Object AttributeSetTranslationId is a composition of the 2 Value Objects (AttribuetSetId and LanguageId)
Anybody have an idea how to configure the key and the conversion for AttributeSet in EF Core Fluent API
So far this is what I got and it doesn't work.
public class AttributeConfigurations : IEntityTypeConfiguration<AttributeSet>
{
public void Configure(EntityTypeBuilder<AttributeSet> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(
attributeSetId => attributeSetId.Value,
value => new AttributeSetId(value));
builder.OwnsMany(builder => builder.AttributeSetTranslations, sb =>
{
sb.ToTable("attribute_set_translations");
sb.HasKey(s => new { s.Id.AttributeSetId, s.Id.LanguageId });
sb.Property(s => s.Id)
.HasConversion(
id => new { id.AttributeSetId, id.LanguageId },
value => new AttributeSetTranslationId(value.AttributeSetId, value.LanguageId));
});
}
}
Here is the error when I'm trying to add the migration.
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: The expression 's => new <>f__AnonymousType92(AttributeSetId = s.Id.AttributeSetId, LanguageId = s.Id.LanguageId)' is not a valid member access expression. The expression should represent a simple property or field access: 't =\> t.MyProperty'. When specifying multiple properties or fields, use an anonymous type: 't =\> new { t.MyProperty, t.MyField }'. (Parameter 'memberAccessExpression') at Microsoft.EntityFrameworkCore.Infrastructure.ExpressionExtensions.GetMemberAccessList(LambdaExpression memberAccessExpression) at Microsoft.EntityFrameworkCore.Metadata.Builders.OwnedNavigationBuilder2.HasKey(Expression1 keyExpression) at ProductCentral.Infrastructure.Persistence.Configurations.AttributeConfigurations.\<\>c.\<Configure\>b__0_5(OwnedNavigationBuilder2 sb) in C:\Source\applive\13500-product-central\backend\ProductCentral.Infrastructure\Persistence\Configurations\AttributeConfigurations.cs:line 23 at Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder1.OwnsMany\[TRelatedEntity\](Expression1 navigationExpression, Action1 buildAction) at ProductCentral.Infrastructure.Persistence.Configurations.AttributeConfigurations.Configure(EntityTypeBuilder1 builder) in \AttributeConfigurations.cs:line 19 at Microsoft.EntityFrameworkCore.ModelBuilder.ApplyConfiguration[TEntity](IEntityTypeConfiguration`1 configuration)at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
I know I could avoid having 2 value objects in AttributeSetTranslationId and simply have a regular ID then add the LanguageId and AttributeSet straight into the Attribute Entity
like that
public class AttributeSetTranslation : Auditable
{
public AttributeSetTranslationId Id { get; private set; }
public LanguageId LanguageId { get; private set; }
public AttributeId AttributeId { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
}
But in my opinion, it would be better to encapsulate the LanguageId and AttributeId in the AttributeSetTranslationId as this is the composite primary key of the object AttributeSetTranslation.
Thanks a lot :)