I am using Entity Framework and am building up a IQueryable<T>
IQueryable<Message> query = db.Messages;
query = query.OrderByDescending(m => m.Created);
query = query.Where(m => m.Deleted == false);
if (lastTime != null)
query = query.Where(m => m.Created < lastTime);
var func = ExpressionHelper.GetPredicate(stream);
query = query.Where(func).AsQueryable; *** ISSUE HERE?? ***
query = query.Skip(skip)
.Take(count)
.Include(m => m.Tags)
.Include(m => m.Properties);
var results = query.ToList();
The issue is the Tags and Properties are not populated in the final list.
I believe it has something to do with the Func<> I am passing in and also believe that after it although AsQueryable is used it doesn't represent IQueryable or does no longer connect to the database.
Is there a way to get Tags and Properties populated?
I'm not sure if making the Func<> to be Expression<Func<>> would help and if so is there a way to convert the below to be Expression<Func<>>
UPDATE:
public static Func<Message, bool> GetPredicate(string expression)
{
Func<Message, bool> result = null;
try
{
ParameterExpression parameter = Expression.Parameter(typeof(Classes.Message), "Message");
var lambda = DynamicExpression.ParseLambda(new[] { parameter }, null, expression);
result = lambda.Compile() as Func<Message, bool>;
}
catch (Exception e)
{
Log.Fatal(e);
}
return result;
}
At this point here:
query.Where(func) // where func is Func<...>
you have switched into LINQ-to-Objects. Anything you do after than (in terms of .Include etc) is irrelevant - you are no longer composing an EF query. You have a thin IQueryable<T> wrapper over a LINQ-to-Objects version of the sequence as it was at that line, i.e.
query = query.Where(func).AsQueryable(); // this is just a thing veneer over L2O
Switching to Expression<Func<...>> is likely to help.
If you absolutely positively can't generate an Expression, you could move the Include etc above this point.
I haven't actually wired this in so it may be slightly off, but as Marc says you've swapped into Linq to Objects at the AsQueryable.
If you remove that call, and then switch the GetPredicate to below it should work. It's the same except that we don't need to compile the lambda, this will happen when the query reaches entity framework.
public static Expression<Func<Message, bool>> GetPredicate(string expression)
{
Expression<Func<Message, bool>> result = null;
try
{
ParameterExpression parameter = Expression.Parameter(typeof(Classes.Message), "Message");
var lambda = DynamicExpression.ParseLambda(new[] { parameter }, null, expression);
result = (Expression<Func<Message, bool>>)lambda;
}
catch (Exception e)
{
Log.Fatal(e);
}
return result;
}
Related
We're trying to implement the "LIKE" operator in Entity Framework for our entities with string fields, but it doesn't appear to be supported. Has anyone else tried to do something like this?
This blog post summarizes the issue we're having. We could use contains, but that only matches the most trivial case for LIKE. Combining contains, startswith, endswith, and indexof gets us there, but requires a translation between standard wildcards and Linq to Entities code.
I don't know anything about EF really, but in LINQ to SQL you usually express a LIKE clause using String.Contains:
where entity.Name.Contains("xyz")
translates to
WHERE Name LIKE '%xyz%'
(Use StartsWith and EndsWith for other behaviour.)
I'm not entirely sure whether that's helpful, because I don't understand what you mean when you say you're trying to implement LIKE. If I've misunderstood completely, let me know and I'll delete this answer :)
Update: In EF 6.2 there is a like operator
Where(obj => DbFunctions.Like(obj.Column , "%expression%"))
This is an old post now, but for anyone looking for the answer, this link should help. Go to this answer if you are already using EF 6.2.x. To this answer if you're using EF Core 2.x
Short version:
SqlFunctions.PatIndex method - returns the starting position of the first occurrence of a pattern in a specified expression, or zeros if the pattern is not found, on all valid text and character data types
Namespace: System.Data.Objects.SqlClient
Assembly: System.Data.Entity (in System.Data.Entity.dll)
A bit of an explanation also appears in this forum thread.
There is LIKE operator is added in Entity Framework Core 2.0:
var query = from e in _context.Employees
where EF.Functions.Like(e.Title, "%developer%")
select e;
Comparing to ... where e.Title.Contains("developer") ... it is really translated to SQL LIKE rather than CHARINDEX we see for Contains method.
I had the same problem.
For now, I've settled with client-side Wildcard/Regex filtering based on http://www.codeproject.com/Articles/11556/Converting-Wildcards-to-Regexes?msg=1423024#xx1423024xx - it's simple and works as expected.
I've found another discussion on this topic: http://forums.asp.net/t/1654093.aspx/2/10
This post looks promising if you use Entity Framework >= 4.0:
Use SqlFunctions.PatIndex:
http://msdn.microsoft.com/en-us/library/system.data.objects.sqlclient.sqlfunctions.patindex.aspx
Like this:
var q = EFContext.Products.Where(x =>
SqlFunctions.PatIndex("%CD%BLUE%", x.ProductName) > 0);
Note: this solution is for SQL-Server only, because it uses non-standard PATINDEX function.
It is specifically mentioned in the documentation as part of Entity SQL. Are you getting an error message?
// LIKE and ESCAPE
// If an AdventureWorksEntities.Product contained a Name
// with the value 'Down_Tube', the following query would find that
// value.
Select value P.Name FROM AdventureWorksEntities.Product
as P where P.Name LIKE 'DownA_%' ESCAPE 'A'
// LIKE
Select value P.Name FROM AdventureWorksEntities.Product
as P where P.Name like 'BB%'
http://msdn.microsoft.com/en-us/library/bb399359.aspx
For EfCore here is a sample to build LIKE expression
protected override Expression<Func<YourEntiry, bool>> BuildLikeExpression(string searchText)
{
var likeSearch = $"%{searchText}%";
return t => EF.Functions.Like(t.Code, likeSearch)
|| EF.Functions.Like(t.FirstName, likeSearch)
|| EF.Functions.Like(t.LastName, likeSearch);
}
//Calling method
var query = dbContext.Set<YourEntity>().Where(BuildLikeExpression("Text"));
if you're using MS Sql, I have wrote 2 extension methods to support the % character for wildcard search.
(LinqKit is required)
public static class ExpressionExtension
{
public static Expression<Func<T, bool>> Like<T>(Expression<Func<T, string>> expr, string likeValue)
{
var paramExpr = expr.Parameters.First();
var memExpr = expr.Body;
if (likeValue == null || likeValue.Contains('%') != true)
{
Expression<Func<string>> valExpr = () => likeValue;
var eqExpr = Expression.Equal(memExpr, valExpr.Body);
return Expression.Lambda<Func<T, bool>>(eqExpr, paramExpr);
}
if (likeValue.Replace("%", string.Empty).Length == 0)
{
return PredicateBuilder.True<T>();
}
likeValue = Regex.Replace(likeValue, "%+", "%");
if (likeValue.Length > 2 && likeValue.Substring(1, likeValue.Length - 2).Contains('%'))
{
likeValue = likeValue.Replace("[", "[[]").Replace("_", "[_]");
Expression<Func<string>> valExpr = () => likeValue;
var patExpr = Expression.Call(typeof(SqlFunctions).GetMethod("PatIndex",
new[] { typeof(string), typeof(string) }), valExpr.Body, memExpr);
var neExpr = Expression.NotEqual(patExpr, Expression.Convert(Expression.Constant(0), typeof(int?)));
return Expression.Lambda<Func<T, bool>>(neExpr, paramExpr);
}
if (likeValue.StartsWith("%"))
{
if (likeValue.EndsWith("%") == true)
{
likeValue = likeValue.Substring(1, likeValue.Length - 2);
Expression<Func<string>> valExpr = () => likeValue;
var containsExpr = Expression.Call(memExpr, typeof(String).GetMethod("Contains",
new[] { typeof(string) }), valExpr.Body);
return Expression.Lambda<Func<T, bool>>(containsExpr, paramExpr);
}
else
{
likeValue = likeValue.Substring(1);
Expression<Func<string>> valExpr = () => likeValue;
var endsExpr = Expression.Call(memExpr, typeof(String).GetMethod("EndsWith",
new[] { typeof(string) }), valExpr.Body);
return Expression.Lambda<Func<T, bool>>(endsExpr, paramExpr);
}
}
else
{
likeValue = likeValue.Remove(likeValue.Length - 1);
Expression<Func<string>> valExpr = () => likeValue;
var startsExpr = Expression.Call(memExpr, typeof(String).GetMethod("StartsWith",
new[] { typeof(string) }), valExpr.Body);
return Expression.Lambda<Func<T, bool>>(startsExpr, paramExpr);
}
}
public static Expression<Func<T, bool>> AndLike<T>(this Expression<Func<T, bool>> predicate, Expression<Func<T, string>> expr, string likeValue)
{
var andPredicate = Like(expr, likeValue);
if (andPredicate != null)
{
predicate = predicate.And(andPredicate.Expand());
}
return predicate;
}
public static Expression<Func<T, bool>> OrLike<T>(this Expression<Func<T, bool>> predicate, Expression<Func<T, string>> expr, string likeValue)
{
var orPredicate = Like(expr, likeValue);
if (orPredicate != null)
{
predicate = predicate.Or(orPredicate.Expand());
}
return predicate;
}
}
usage
var orPredicate = PredicateBuilder.False<People>();
orPredicate = orPredicate.OrLike(per => per.Name, "He%llo%");
orPredicate = orPredicate.OrLike(per => per.Name, "%Hi%");
var predicate = PredicateBuilder.True<People>();
predicate = predicate.And(orPredicate.Expand());
predicate = predicate.AndLike(per => per.Status, "%Active");
var list = dbContext.Set<People>().Where(predicate.Expand()).ToList();
in ef6 and it should translate to
....
from People per
where (
patindex(#p__linq__0, per.Name) <> 0
or per.Name like #p__linq__1 escape '~'
) and per.Status like #p__linq__2 escape '~'
', #p__linq__0 = '%He%llo%', #p__linq__1 = '%Hi%', #p__linq_2 = '%Active'
You can use a real like in Link to Entities quite easily
Add
<Function Name="String_Like" ReturnType="Edm.Boolean">
<Parameter Name="searchingIn" Type="Edm.String" />
<Parameter Name="lookingFor" Type="Edm.String" />
<DefiningExpression>
searchingIn LIKE lookingFor
</DefiningExpression>
</Function>
to your EDMX in this tag:
edmx:Edmx/edmx:Runtime/edmx:ConceptualModels/Schema
Also remember the namespace in the <schema namespace="" /> attribute
Then add an extension class in the above namespace:
public static class Extensions
{
[EdmFunction("DocTrails3.Net.Database.Models", "String_Like")]
public static Boolean Like(this String searchingIn, String lookingFor)
{
throw new Exception("Not implemented");
}
}
This extension method will now map to the EDMX function.
More info here: http://jendaperl.blogspot.be/2011/02/like-in-linq-to-entities.html
In short, I'm looking to do what this guy did, but with Entity Framework 6.
Implementing the proposed solution results in the error "The LINQ expression node type 'Invoke' is not supported in LINQ to Entities." Since the proposed solution uses Invoke, this is obviously an issue.
I understand that there's a way to harness a custom Compose method to rewrite the expression tree without using Invoke, but I can't seem to wrap my head around it.
Here's what I'm trying to write.
I build an IQueryable<TEntity> dynamically using a QueryParameters object that's just a bag of properties to use for the WHERE clauses. TEntity is a standard code-first EF entity with data annotations all over the place. The query contruction looks something like this:
IQueryable<TEntity> query = Context.Set<TEntity>();
if (queryParams == null)
return query;
if (!string.IsNullOrWhiteSpace(queryParams.FirstName))
{
if (queryParams.ExactSearch)
{
query = query.Where(x => x.FirstName == queryParams.FirstName);
}
else
{
if (queryParams.PreferStartsWith)
{
query = query.Where(
x => x.FirstName.ToLower()
.StartsWith(
queryParams.FirstName
.ToLower()));
}
else
{
query = query.Where(
x => x.FirstName.ToLower()
.Contains(
queryParams.FirstName
.ToLower()));
}
}
}
// ... repeat for all of queryParams' string props.
// DateTime, int, bool, etc have their own filters.
This gets repeated for every query parameter for a string field to be queried. Obviously, this results in a lot of repeated code. I would love to be able to write a filter with a signature like this:
public static IQueryable<TEntity> Search<TEntity>(
this IQueryable<TEntity> query,
Expression<Func<TEntity, string>> fieldExpression,
string searchValue,
bool exactSearch = true,
bool useStartsWithOverContains = false) {...}
Which I can then consume like this:
if (!string.IsNullOrWhiteSpace(queryParams.FirstName))
{
query = query.Search(
x => x.FirstName,
queryParams.FirstName,
queryParams.ExactSearch,
queryParams.PreferStartsWith);
}
The closest I've come a definition for that extension method is the below, but as mentioned, it produces that "'Invoke' is not supported in LINQ to Entities" error:
public static IQueryable<TEntity> Search<TEntity>(
this IQueryable<TEntity> query,
Expression<Func<TEntity, string>> fieldExpression,
string searchValue,
bool exactSearch = true,
bool useStartsWithOverContains = false)
{
if (string.IsNullOrWhiteSpace(searchValue))
return query;
searchValue = searchValue.Trim();
Expression<Func<TEntity, bool>> expression;
if (exactSearch)
{
var x = Expression.Parameter(typeof(TEntity), "x");
var left = Expression.Invoke(fieldExpression, x);
var right = Expression.Constant(searchValue);
var equalityExpression = Expression.Equal(left, right);
expression = Expression.Lambda<Func<TEntity, bool>>(
equalityExpression,
x);
}
else
{
searchValue = searchValue.ToLower();
var x = Expression.Parameter(typeof(TEntity), "x");
var fieldToLower = Expression.Call(
Expression.Invoke(fieldExpression, x),
typeof(string).GetMethod(
"ToLower",
Type.EmptyTypes));
var searchValueExpression =
Expression.Constant(searchValue);
var body = Expression.Call(
fieldToLower,
typeof(string).GetMethod(
useStartsWithOverContains ? "StartsWith" : "Contains",
new[] { typeof(string) }),
searchValueExpression);
expression = Expression.Lambda<Func<TEntity, bool>>(
body,
x);
}
return query.Where(expression);
}
I started to include the Compose method I mentioned, but I got lost really quickly, and thus removed it.
Open to any guidance! Thank you!
This is much easier to do by composing expressions than it is by trying to manually construct the expressions every single time. It's faster to write, so much less error prone, and actually ends up with code you can actually read at the end of it. All you need to do is write the code for how you use the value in the composed expression, which you already have from your original code.
public static IQueryable<TEntity> Search<TEntity>(
this IQueryable<TEntity> query,
Expression<Func<TEntity, string>> fieldExpression,
string searchValue,
bool exactSearch = true,
bool useStartsWithOverContains = false)
{
if (string.IsNullOrWhiteSpace(searchValue))
return query;
searchValue = searchValue.Trim();
if (exactSearch)
{
return query.Where(fieldExpression.Compose(field => field == searchValue));
}
else if (useStartsWithOverContains)
{
return query.Where(fieldExpression.Compose(field => field.StartsWith(searchValue.ToLower())));
}
else
{
return query.Where(fieldExpression.Compose(field => field.Contains(searchValue.ToLower())));
}
}
Note you should probably go with an enum for "Comparison" or something like that, rather than having two booleans. For example, right now someone can say that they don't want an exact sure but that they do want to use starts with. Just have one parameter with the three options.
I have a generic class with a method that needs to sort a generic entity.
However, an error occurs saying that it does not recognize the Reflection GetProperty method, since lambda can not translate.
How can I do this sort ordering logic?
public IEnumerable<TEntity> GetAll()
{
var obj = _repository.GetAll()
.OrderByDescending(x => x.GetType().GetProperty(typeof(TEntity).Name + "Id"));
return obj.Pagination();
}
Here is the error image:
The error says it all.
Linq to Entities doesn't know how to translate x.GetType().GetProperty(typeof(TEntity).Name + "Id") into SQL.
You can materialize the results first, so it'll be linq to objects:
_repository.GetAll().ToList()
.OrderByDescending(x => x.GetType().GetProperty(typeof(TEntity).Name + "Id"));
You can use _repository.GetAll().Queryable().OrderByDescending(x => x.GetType().GetProperty(typeof(TEntity).Name + "Id"));
To build a LINQ query dynamically, use Expression Trees. This is how your method may look like:
public IEnumerable<TEntity> GetAll()
{
IQueryable<TEntity> obj = _repository.GetAll();
PropertyInfo keyProperty = typeof(TEntity).GetProperty(string.Concat(typeof(TEntity).Name, "Id"));
Expression parameter = Expression.Parameter(typeof(TEntity));
Expression predicate = Expression.Lambda(Expression.Property(parameter, keyProperty), parameter);
Expression queryExpression = Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { typeof(TEntity), keyProperty.PropertyType }, obj, predicate);
obj = obj.Provider.CreateQuery<TEntity>(queryExpression);
return obj.Pagination();
}
Problem
I'm working on refactoring some LINQ queries for several reports in our web application, and I'm attempting to move some duplicate query predicates into their own IQueryable exension methods so we can reuse them for these reports, and reports in the future. As you can probably infer, I've already refactored the predicate for groups, but the predicate for codes is giving me problems. This is an example of one of the report methods I have so far:
DAL method:
public List<Entities.QueryView> GetQueryView(Filter filter)
{
using (var context = CreateObjectContext())
{
return (from o in context.QueryViews
where (!filter.FromDate.HasValue || o.RepairDate >= EntityFunctions.TruncateTime(filter.FromDate))
&& (!filter.ToDate.HasValue || o.RepairDate <= EntityFunctions.TruncateTime(filter.ToDate))
select o)
.WithCode(filter)
.InGroup(filter)
.ToList();
}
}
IQueryable Extension:
public static IQueryable<T> WithCode<T>(this IQueryable<T> query, Filter filter)
{
List<string> codes = DAL.GetCodesByCategory(filter.CodeCategories);
if (codes.Count > 0)
return query.Where(Predicates.FilterByCode<T>(codes));
return query;
}
Predicate:
public static Expression<Func<T, List<string>, bool>> FilterByCode<T>(List<string> codes)
{
// Method info for List<string>.Contains(code).
var methodInfo = typeof(List<string>).GetMethod("Contains", new Type[] { typeof(string) });
// List of codes to call .Contains() against.
var instance = Expression.Variable(typeof(List<string>), "codes");
var param = Expression.Parameter(typeof(T), "j");
var left = Expression.Property(param, "Code");
var expr = Expression.Call(instance, methodInfo, Expression.Property(param, "Code"));
// j => codes.Contains(j.Code)
return Expression.Lambda<Func<T, List<string>, bool>>(expr, new ParameterExpression[] { param, instance });
}
The problem I'm having is that Queryable.Where doesn't accept a type of Expression<Func<T, List<string>, bool>. The only way I can think of creating this predicate dynamically is to use two parameters, which is the part that is really stumping me.
What I'm not comprehending is the following method works. I can pass the exact lambda expression I am trying to create dynamically, and it correctly filters my data.
public List<Entities.QueryView> GetQueryView(Filter filter)
{
// Get the codes here.
List<string> codes = DAL.GetCodesByCategory(filter.CodeCategories);
using (var context = CreateObjectContext())
{
return (from o in context.QueryViews
where (!filter.FromDate.HasValue || o.RepairDate >= EntityFunctions.TruncateTime(filter.FromDate))
&& (!filter.ToDate.HasValue || o.RepairDate <= EntityFunctions.TruncateTime(filter.ToDate))
select o)
.Where(p => codes.Contains(p.Code)) // This works fine.
//.WithCode(filter)
.InGroup(filter)
.ToList();
}
}
Questions
Can I implement my own Queryable.Where overload? If so, is it even feasible?
If an overload isn't feasible, is there a way to dynamically construct the predicate p => codes.Contains(p.Code) without using two parameters?
Is there an easier way to do this? I feel like I'm missing something.
You can create your own extension method, name it Where, accept an IQueryable<T>, return an IQueryable<T>, and otherwise make it emulate the form of LINQ methods. It wouldn't be a LINQ method, but it would look like one. I would discourage you from writing such a method simply because it would likely confuse others; even if you want to make a new extension method, use a name not used in LINQ to avoid confusion. In short, do what you're doing now, create new extensions without actually naming them Where. If you really wanted to name one Where though nothing's stopping you.
Sure, just use a lambda:
public static Expression<Func<T, bool>> FilterByCode<T>(List<string> codes)
where T : ICoded //some interface with a `Code` field
{
return p => codes.Contains(p.Code);
}
If you really cannot have your entities implement an interface (hint: you almost certainly can), then the code would look identical to the code that you have, but using the list that you pass in as a constant rather than a new parameter:
public static Expression<Func<T, bool>> FilterByCode<T>(List<string> codes)
{
var methodInfo = typeof(List<string>).GetMethod("Contains",
new Type[] { typeof(string) });
var list = Expression.Constant(codes);
var param = Expression.Parameter(typeof(T), "j");
var value = Expression.Property(param, "Code");
var body = Expression.Call(list, methodInfo, value);
// j => codes.Contains(j.Code)
return Expression.Lambda<Func<T, bool>>(body, param);
}
I would strongly encourage use of the former method; this method loses static type safety, and is more complex and as such harder to maintain.
Another note, the comment you have in your code: // j => codes.Contains(j.Code) isn't accurate. What that lambda actually looks like is: (j, codes) => codes.Contains(j.Code); which is actually noticeably different.
See the first half of #2.
I have a method in my project that repeats over and over:
public PAC PAC_GetByCodiPac(string codiPac)
{
var sel = _gam.PAC.Where(pac => pac.CODI_PAC == codiPac);
if (sel.Count() > 0)
return sel.First();
return null;
}
The table PAC means (patient), so I have these methods for all the tables I have.
How can I make a generic method for this?
Thanks in advance.
Here is your generic method. Note, that as others pointed out FirstOrDefault is better than count and then first, so I'm using it here. But it's also possible to write the expression so that it mimics what your original code does. Please let me know if you need additional help with this.
public static T GetByCodi<T>(IQueryable<T> table, string codi, string fieldName) where T : class
{
// x
ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
Expression currentExpression = parameter;
Type currentType = typeof(T);
PropertyInfo property = currentType.GetProperty(fieldName);
// x.CODI_xxx
currentExpression = Expression.Property(currentExpression, property);
// x.CODI_xxx == codi
currentExpression = Expression.Equal(currentExpression, Expression.Constant(codi));
// x => x.CODI_xxx == codi
LambdaExpression lambdaExpression = Expression.Lambda(currentExpression, parameter);
return table.FirstOrDefault((Func<T, bool>)lambdaExpression.Compile());
}
You use it like this:
PAC xxx = GetByCodi<PAC>(_gam.PAC, codiPac, "CODI_PAC");
Edit 1:
I changed the code according to the comment so that you can pass arbitrary ID field name in.
I see that what you asked is a very straight forward where query even doesn't require to have have it on a separate method.
Also you can simply enhance your query link the following:
public PAC PAC_GetByCodiPac(string codiPac)
{
return _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);
}
FirstOrDefault will return the first item on the array, if not it will return null.
If you want a generic method that lets you specify any table and any predicate for records from that table then you can't really get any better than the built-in Where<T>(...) and (as others have already pointed out) the FirstOrDefault<T>(...) extension methods.
Your code would then look like so:
var result = _gam.PAC.Where(pac => pac.CODI_PAC == codiPac).FirstOrDefault();
// OR
var result = _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);
The best you could get then, writing your own generic method, would be this:
public T FirstOrDefault<T>(IQueryable<T> source,
Expression<Func<T, bool>> predicate)
{
return source.Where(predicate).FirstOrDefault();
// OR
// return source.FirstOrDefault(predicate);
}
And that is really just redundant. Especially when your calling code would be actually longer using the helper method:
var result = FirstOrDefault(_gam.PAC, pac => pac.CODI_PAC == codiPac);
// versus
var result = _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);
And even worse, your code is no longer using a fluent, composable syntax. This just makes readability and maintenance more difficult.
If you stick with using the IQueryable<T> extension methods then you can do composition like this:
var result = _gam.PAC
.Where(pac => pac.CODI_PAC == codiPac)
.Where(pac => pac.SomeOtherProperty == someOtherValue)
.FirstOrDefault();
// OR
var result = (from pac in _gam.PAC
where pac.CODI_PAC == codiPac
where pac.SomeOtherProperty == someOtherValue
select pac).FirstOrDefault();
One very important thing to note here is that the predicate parameter in the IQueryable<T>.Where<T>(...) extension method is of type Expression<Func<T, bool>>. This allows the IQueryable<T> provider to construct the native SQL (or other native provider query) at the very last moment before returning a result.
Not using Expression<Func<T, bool>> means that your query would be the equivalent of this:
var result =
_gam.PAC
.ToArray()
.Where(pac => pac.CODI_PAC == codiPac)
.FirstOrDefault();
And that would mean the query will load every record from the "PAC" table into memory before selecting the first filtered result and throwing out the rest of the results.
The bottom-line is that by making a generic helper method you are rewriting existing framework code and you open yourself to performance and maintenance issues while also reducing code readability.
I hope this helps.
I'm not sure if you are asking for this, but this method could be in a static class and method and so you'd be able to call it from everywhere.
An easy solution will be:
//a generic method
private PAC PAC_GetPAC(Func<PAC, bool> predicate)
{
return _gam.PAC.Where(predicate).FirstOrDefault();
}
public PAC PAC_GetPACById(long id)
{
return PAC_GetPAC(p => p.ID == id);
}
public PAC PAC_GetByCodiPac(string codiPac)
{
return PAC_GetPAC(p => pac.CODI_PAC == codiPac);
}