Open jyscao opened 2 years ago
I'm not that experienced with EF, but maybe this will work?
[Column(TypeName = "int, not null")] // explicitly map the SQL data type to `int`
public LongId Id { get; set; }
Failing something like that, you're probably better off using something like AutoMapper to separate your entities (classes that map 1:1 to fields in your database and are only used in code that directly interacts with the DB) and your models (classes that use ValueOf).
Vogen is similar to this but it has certain opinions/constraints on safety (for instance, not being able to create default instances of value objects). It's also focused on speed; there's almost no overheard compared to using a primitive directly. It's a source generator, and can generate code for EF (as well as Json and Dapper). I'm not after stealing customers away from this very useful little package, but you might find it has what you need (if you're happy with the constraints it imposes)
@chucker tried your suggestion just now, same error as before. In fact even when I annotate the property with [NotMapped]
, the same error still pops up. So I get the feeling that I haven't even been addressing the issue at the right level. To me EFCore definitely contains enough magic that I'm not even sure where to really start looking into this. Thanks anyway for trying to help.
@SteveDunn thanks for the tip, for the time being I've switched back to working in primitive obsession mode just because I want to make progress on the actual code I gotta get done (it's for work unfortunately). But I'll keep your package in mind for when I do the refactoring down the line, hopefully sooner rather than later.
I haven't really used EF for a while, but I suspect you need a custom ValueConverter https://docs.microsoft.com/en-us/ef/core/modeling/value-conversions?tabs=data-annotations
Another option might be https://docs.microsoft.com/en-us/ef/core/modeling/backing-field?tabs=data-annotations
Using value conversions with ValueOf works perfectly fine.
public class CustomerContext : DbContext
{
public CustomerContext(DbContextOptions options) : base(options)
{
}
public DbSet<Customer> Customers => Set<Customer>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Customer>()
.Property(e => e.Id)
.HasConversion(
convertToProviderExpression: id => id.Value,
convertFromProviderExpression: id => CustomerId.From(id));
modelBuilder
.Entity<Customer>()
.Property(e => e.Email)
.HasConversion(
convertToProviderExpression: emailAddress => emailAddress.Value,
convertFromProviderExpression: emailAddress => EmailAddress.From(emailAddress));
}
}
Check out my repository for a fully working example: https://github.com/ttlaare/ValueOfWithEf
If you want a generic ValueOfConverter:
public class ValueOfConverter<T, TType> : ValueConverter<T, TType>
where T : ValueOf<TType, T>, new()
{
public ValueOfConverter() : base(
id => id.Value,
id => ValueOf<TType, T>.From(id))
{
}
}
builder.Property(x => x.Foobar).HasConversion<ValueOfConverter<Foobar, int>>();
Hi, I'm trying to incorporate your excellent library into my EFCore model classes, for example:
Where
LongId
,NameLabel
,GuidStr
have C# primitive types oflong
,string
,string
respectively, with appropriate validation checks (e.g. under a certain length forNameLabel
, and of certain format forGuidStr
).The code compiles fine, however when I actually try to fetch one of the above record from the database, I'm running into this error:
System.InvalidOperationException: The property 'Account.Id' is of type 'LongId' which is not supported by the current database provider. Either change the property CLR type, or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
I also tried to annotate the model with something like
[Column(TypeName = "bigint")]
on theId
property for example, and it didn't do anything. So I just wanted to ask you if what I'm trying to do is reasonable and/or feasible. Maybe I should just return to using primitive C# types?