Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search by value object's Value property: Translation error #399

Closed
jtrose22 opened this issue May 9, 2024 · 3 comments
Closed

Search by value object's Value property: Translation error #399

jtrose22 opened this issue May 9, 2024 · 3 comments

Comments

@jtrose22
Copy link

jtrose22 commented May 9, 2024

I have a defined value object called Title, which exposes its value through a property called "Value" (i.e. Title.Value). I am using EF Core 8.0 and have the value object defined as:

builder
    .Property(x => x.Title)
    .HasConversion(x => x.Value, x => Title.Create(x).Value)
    .HasMaxLength(Title.MaxLength)
    .IsRequired();

When I try to use the Query.Search() function, I am receiving an error that it could not be translated.
Examples:

Query.Search(x => x.Title.Value, filter);
Query.Search(x => x.Title.ToString(), filter);
Query.Search(x => EF.Property<string>(x, "Title"), filter);
Query.Where(x => x.Title.Value.Contains(searchFilter));

Error:

The LINQ expression 'DbSet<Books>()
    .Where(s => __Functions_0
        .Like(
            matchExpression: s.Title.Value, 
            pattern: __criteria_SearchTerm_1))' 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 know this isn't directly related to the specification package, but I'm looking for some help and maybe a new feature.
Maybe something along the lines of:

Query.Search(x => x.Title, filter, translation: t => t.Title.Value);

Is there another approach I could take to use this value object in the search?

@enrij
Copy link

enrij commented May 10, 2024

If i got it right your Book object is something like

public sealed class Book
{
    // ...
    public Title Title { get; set; }
}

and your Title object is like

public struct Title
{
    private string _value;

    public string Value => _value;

    public short MaxLength => 200;

    public static Title Create(string title)
    {
        // checks on input ...

        _value = title;
    }
}

in this case your conversion for the Title property should be

builder
    .Property(x => x.Title)
    .HasConversion(x => x.Value, x => Title.Create(x)) // <-- Remove the final .Value from Title.Create()
    .HasMaxLength(Title.MaxLength)
    .IsRequired() // This can be omitted if title is not null in Book 

@jtrose22
Copy link
Author

@enrij That's almost exactly what I have, but my Title.Create() function returns either errors or the Title object. So the Title.Create(x).Value is needed in the EF Core configuration. I am using the ErrorOr library so the actual method looks like:

public static ErrorOr<Title> Create(string title);

Do you think because I have it configured that way, it's the cause of the issue with translation? I'll change the code a bit and see if that is indeed the issue.

I did find a work around to my issue, but it's not pretty.

Query.Where(x => ((string)(object)x.Title).Contains(filter)); <--- Works
Query.Search(x => x.Title.Value, filter); <--- Does not work

@jtrose22
Copy link
Author

jtrose22 commented May 10, 2024

I found my issue. I misconfigured the EF configuration. My original configuration worked in almost every case until I tried to use it in the Search. I then realized that some of my objects worked fine in search, such as Author.Email. The Author object is setup as a complex property, while my Title is not.

I changed:

builder
    .Property(x => x.Title)
    .HasConversion(x => x.Value, x => Title.Create(x).Value)
    .HasMaxLength(Title.MaxLength)
    .IsRequired();

to

builder
    .ComplexProperty(x => x.Title, b =>
    {
        b.Property(x => x.Value)
        .HasColumnName("Title")
        .HasMaxLength(Title.MaxLength)
        .IsRequired();
    });

And now I can use the following:

Query.Search(x => x.Title.Value, filter);

Thanks @enrij, you set my mind in the right direction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants