scottksmith95 / LINQKit

LINQKit is a free set of extensions for LINQ to SQL and Entity Framework power users.
MIT License
1.65k stars 165 forks source link

how to do apply LINQ using ExpressionBuilder on NotMapped property #187

Open furanzKafka opened 1 year ago

furanzKafka commented 1 year ago

i have [NotMapped] property in entity, i want to apply filter on this property like this

public class MyEntity : IEntity { public Guid ID { get; set; } public string Code { get; set; } public string Description { get; set; } [NotMapped] public string CodeAndDescription => Code + " / " + Description; }

var pre = ExpressionBuilder.New(true); if (filter.PublicFilter != null) { string keywords = filter.PublicFilter.ToLower().Replace("İ", "i").Replace("ı", "i");

pre.And(x => x.CodeAndDescription.ToLower().Replace("İ", "i").Replace("ı", "i").Contains(keywords));

}

Of course, a solution can be found in these codes by applying a separate LINQ for Code and a separate LINQ for Description. This solution will not work when there is a more complex situation. But I simply wrote these codes to ask how to apply LINQ to a NotMapped field with expressionbuilder.

how can I do that

TheConstructor commented 1 year ago

Hey @furanzKafka,

not sure what ExpressionBuilder is in this context; so I will assume you refer to PredicateBuilder. Your main problem also seems to be EF Core not knowing what a [NotMapped] property is. You can use [Expandable(methodName)] + .Expand() to replace the property by an EF Core mappable expression, though it may not be the optimal expression for your query:

    public class MyEntity
    {
        public Guid ID { get; set; }
        public string Code { get; set; }
        public string Description { get; set; }
        [NotMapped]
        [Expandable(nameof(CodeAndDescriptionExpr))]
        public string CodeAndDescription => Code + " / " + Description;
        private static Expression<Func<MyEntity, string>> CodeAndDescriptionExpr() => e => e.Code + " / " + e.Description;
    }

    public class ExpressionBuilderTest {

        [Fact]
        public void ExpressionIsAppliedToMappedProperties()
        {
            var pre = PredicateBuilder.New<MyEntity>(true);
            var keywords = "?";
            pre = pre.And(x => x.CodeAndDescription.ToLower().Replace("İ", "i").Replace("ı", "i").Contains(keywords));
            var fin = pre.Expand();
            Assert.Equal(
                $"x => ((x.Code + \" / \") + x.Description).ToLower().Replace(\"İ\", \"i\").Replace(\"ı\", \"i\").Contains(value({typeof(ExpressionBuilderTest).FullName}+<>c__DisplayClass0_0).keywords)",
                fin.ToString());
        }
    }

If you know, that filter.PublicFilter does not contain / it may be better to search in Code and Description on their own, without concatenating them first.

Hope this gives you some ideas