Closed ardalis closed 1 month ago
If nothing else, I wonder if we could have something in a separate project that would work like this:
[ValueConverter<ProjectName>(Converters.EFCore)]
public partial ProjectNameConverter();
You could define separate ones (in separate projects if desired) for different converters, or use the | syntax to put several into one class.
How easy/hard would this be?
Ok as a workaround I have this working:
// in Core project - note no reference to EF Core here and I removed all references from the .csproj
[ValueObject<string>(conversions: Conversions.SystemTextJson)]
public partial class ProjectName
{
private static Validation Validate(in string name) => String.IsNullOrEmpty(name) ?
Validation.Invalid("Name cannot be empty") :
Validation.Ok;
}
// in Infrastructure project with DbContext (and EF Core package references)
using NimblePros.SampleToDo.Core.ProjectAggregate;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vogen;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.EntityFrameworkCore.ChangeTracking;
namespace NimblePros.SampleToDo.Infrastructure.Data.Config;
public class ProjectConfiguration : IEntityTypeConfiguration<Project>
{
public void Configure(EntityTypeBuilder<Project> builder)
{
builder.Property(p => p.Name)
//.HasVogenConversion()
.HasConversion(new EfCoreValueConverter(), new EfCoreValueComparer())
.HasMaxLength(DataSchemaConstants.DEFAULT_NAME_LENGTH)
.IsRequired();
builder.Property(p => p.Priority)
.HasConversion(
p => p.Value,
p => Priority.FromValue(p));
}
public class EfCoreValueConverter : ValueConverter<ProjectName, String>
{
public EfCoreValueConverter() : this(null)
{
}
public EfCoreValueConverter(ConverterMappingHints mappingHints = null)
: base(vo => vo.Value, value => ProjectName.From(value), mappingHints)
{
}
}
public class EfCoreValueComparer : ValueComparer<ProjectName>
{
public EfCoreValueComparer() : base((left, right) => DoCompare(left, right),
instance => instance.IsInitialized() ? instance.Value.GetHashCode() : 0)
{
}
static bool DoCompare(ProjectName left, ProjectName right)
{
// if both null, then they're equal
if (left is null)
return right is null;
// if only right is null, then they're not equal
if (right is null)
return false;
// if they're both the same reference, then they're equal
if (ReferenceEquals(left, right))
return true;
// if neither are initialized, then they're equal
if (!left.IsInitialized() && !right.IsInitialized())
return true;
return left.IsInitialized() && right.IsInitialized() && left.Value.Equals(right.Value);
}
}
}
Basically I looked at the generated code and copied it out into my Configuration class. I had to change _value to Value in a few places and a call to _Deserialize(string) to just From(string) but otherwise it was pretty simple. And then I specified the types directly instead of having the handy Vogen helper:
//.HasVogenConversion()
.HasConversion(new EfCoreValueConverter(), new EfCoreValueComparer())
So, it works this way, but this will result in lots of duplicate code, which is what Vogen is great at. I'm hoping someone can move/copy the code generation for EF Core converter/comparer so that it can be applied to a class in a separate project (and maybe adjust HasVogenConversion
to be able to discover it as well).
Thanks!
Hi @ardalis - yes, this is possible and is documented here: https://stevedunn.github.io/Vogen/efcoreintegrationhowto.html Hopefully that'll work for you, but please let me know if there's any issues or if the process could be improved.
Closing, but do let me know if you have any further questions if this isn't resolved.
No this is perfect and I'm glad you'd already thought to do it. I just didn't see it in the docs (I did look...). Thanks!
Describe the feature
I'm trying to generate a VO for a Name in my Core project which has no references to EF Core. However, the generated code has errors at compile time, saying
This issue is that I don't have EF Core referenced from this project, nor do I want to do so. That is only referenced from my Infrastructure project, which is also where my DbContext and all of my EF configuration classes are.
Is there a way to generate the converters in the Infrastructure project rather than in the VO itself?
My Value Object (in Core project)