C
C#2y ago
demndev

✅ ef core can't translate a query

query:
var username = "some username";
var user = await _db.Users
.FirstOrDefaultAsync(u => u.Username.Value == username);
var username = "some username";
var user = await _db.Users
.FirstOrDefaultAsync(u => u.Username.Value == username);
UserConfiguration:
public void Configure(EntityTypeBuilder<UserEntity> builder)
{
builder.HasKey(u => u.Id);

builder.Property(u => u.Username)
.HasConversion(
u => u.Value,
value => new Username(value));

builder.Property(u => u.Password)
.HasConversion(
p => p.Value,
value => Password.FromValue(value));
}
public void Configure(EntityTypeBuilder<UserEntity> builder)
{
builder.HasKey(u => u.Id);

builder.Property(u => u.Username)
.HasConversion(
u => u.Value,
value => new Username(value));

builder.Property(u => u.Password)
.HasConversion(
p => p.Value,
value => Password.FromValue(value));
}
Password VO:
public class Password
{
public string Value { get; private set; }
private readonly IPasswordHasher _passwordHasher;

private Password(string value)
{
Value = value;
_passwordHasher = null!;
}

private Password(string value, IPasswordHasher passwordHasher)
{
_passwordHasher = passwordHasher;
Value = value;
}

public static Password Create(string value, IPasswordHasher passwordHasher)
{
Validate(value);

return new(passwordHasher.GetHash(value), passwordHasher);
}

public static Password FromValue(string value)
{
return new Password(value);
}

public void Update(string newValue)
{
Validate(newValue);

Value = _passwordHasher.GetHash(newValue);
}

private static void Validate(string value)
{
if (value.Length is not (<= 100 and >= 8))
throw new Exceptions.InvalidPasswordLengthException();
}
}
public class Password
{
public string Value { get; private set; }
private readonly IPasswordHasher _passwordHasher;

private Password(string value)
{
Value = value;
_passwordHasher = null!;
}

private Password(string value, IPasswordHasher passwordHasher)
{
_passwordHasher = passwordHasher;
Value = value;
}

public static Password Create(string value, IPasswordHasher passwordHasher)
{
Validate(value);

return new(passwordHasher.GetHash(value), passwordHasher);
}

public static Password FromValue(string value)
{
return new Password(value);
}

public void Update(string newValue)
{
Validate(newValue);

Value = _passwordHasher.GetHash(newValue);
}

private static void Validate(string value)
{
if (value.Length is not (<= 100 and >= 8))
throw new Exceptions.InvalidPasswordLengthException();
}
}
10 Replies
demndev
demndevOP2y ago
and the UserEntity:
public class UserEntity : EntityBase
{
public Username Username { get; }
public Password Password { get; } // TODO: work with password hashing
private List<NoteEntity> _notes = new();
public IEnumerable<NoteEntity> Notes => _notes.AsReadOnly();

public UserEntity(Password password, Username username)
{
Password = password;
Username = username;
}

public bool Authenticate(Username username, Password password)
{
return Username.Value == username.Value && Password.Value == password.Value;
}
public class UserEntity : EntityBase
{
public Username Username { get; }
public Password Password { get; } // TODO: work with password hashing
private List<NoteEntity> _notes = new();
public IEnumerable<NoteEntity> Notes => _notes.AsReadOnly();

public UserEntity(Password password, Username username)
{
Password = password;
Username = username;
}

public bool Authenticate(Username username, Password password)
{
return Username.Value == username.Value && Password.Value == password.Value;
}
what am i doing wrong? exception:
The LINQ expression 'DbSet<UserEntity>()
.Where(u => u.Username.Value == __username_0)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
The LINQ expression 'DbSet<UserEntity>()
.Where(u => u.Username.Value == __username_0)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
i also tried using .HasColumnName, but it didn't help
JakenVeina
JakenVeina2y ago
why in the world is Username its own class? or struct? u.Username.Value is invalid Username is not an entity type you've registered with EF, so it doesn't know how to navigate .Value and the value conversion you've defined doesn't help all that does is tell EF to store that column as a string, and how to convert the two back and forth as yhey go to and from the database
jcotton42
jcotton422y ago
smells of DDD
private List<NoteEntity> _notes = new();
public IEnumerable<NoteEntity> Notes => _notes.AsReadOnly();
private List<NoteEntity> _notes = new();
public IEnumerable<NoteEntity> Notes => _notes.AsReadOnly();
what's up with this? @demndev you're trying to be wayyyyyy too clever with your entities some cleverness is fine, like in my Discord bots I have a value converter for Snowflake that converts it to/from ulong but generally your database entities should just be data no cleverness
demndev
demndevOP2y ago
it's a value object yes, it's something like DDD
jcotton42
jcotton422y ago
you can set up a value converter but then you need to use Username opaquely i.e. just do someUsername == anotherUsername not someUsername.Value == anotherUsername.Value
demndev
demndevOP2y ago
okay… what is a value converter and how can i set up it?
jcotton42
jcotton422y ago
it's the HasConversion stuff you're already doing so if the drop the .Value stuff, it should all work
demndev
demndevOP2y ago
thanks!
jcotton42
jcotton422y ago
remember, EF isn't actually running the expressions you give it it's translating them to SQL so it's looking for a column to act on and your Username column doesn't have a Value property in the database
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server