Generic function to check if value exists within DbSet - c#

If I have multiple dbSets within my dbContext, for example:
public DbSet Persons { get; set; }
public DbSet Companies { get; set; }
public DbSet<...>
How could I than create a generic function to check if the value of a dynamically passed field already occurs?
Function in pseudo code:
bool IsFieldValueUnique<T>(field, fieldValue)
{
return DbSet<T>.Any(x => x.field == fieldValue)
}
And function calls could then be something like:
var result1 = IsFieldValueUnique<Person>(Person.Email, somePersonObject.Email)
var result2 = IsFieldValueUnique<Company>(Company.Identification, someCompanyObject.Identification)
When searching around, I find approaches like using '<Func<T, bool>>', but can't connect the dots together.

Func<T, bool> - Sounds like the right approach to what you want.
bool IsFieldValueUnique<T>(Func<T, bool> checkFunction)
{
var alreadyExists = DbSet<T>.Any(checkFunction);
return !alreadyExists;
//Other ways to do this, but this is just for clarity.
}
Then you call it like:
IsFieldValueUnique<Person>(person => person.Email == somePersonObject.Email)
What you have now is a method IsFieldValueUnique that takes a check function.
This check function takes in a T (of the same type as you use in the DbSet) and returns a boolean value.
person => person.Email == somePersonObject.Email is an anonymous function that for a given instance of a Person compare the Email property with somePersonObject.Email.
If you look at the signature for Any you will see similarities with the checkFunction signature.
If you want to try it on Customer you can:
IsFieldValueUnique<Customer>(cust => person.Name == someCustomer.Name);
Note:
Calling Any like this: DbSet<T>.Any(checkFunction);
Is the same as this: DbSet<T>.Any(item => checkFunction(item));

bool IsFieldValueUnique<T>(Expression<Func<T, bool>> predicate)
{
return DbSet<T>.AsQueryable().Any(predicate.Compile());
}
And use it like this:
bool unique = IsFieldValueUnique<Person>(p => p.Email == something.Email);

Related

Is it possible to create in C# a predicate with a custom values, or templated values

I am relatively new to C# and come from a C++ background. I have been looking a list searches and the usages of Find.
I am trying to define a function that takes a parameter, and returns an entry from a list. for example
class Product
{
public string id;
public string description;
}
public List<Product> products = new List<Product>();
// Add some items to the list
My question is, can I turn this following custom "Find" function using C# features like Predicates/Funcs
Product GetProductByID(string id)
{
foreach (Product p in products)
{
if (p.id == id)
{
return p;
}
}
}
I have tried using Predicates, but I don't seem to be able to find anyway to feed a value in to the function to do the boolean expression check against. I understand how I would write a Predicate to find a speciic item in a list, but not a dynamic one that could be passed in.
Ideally I would then like to go one step further and Template it so the Predicate could be used for any list of items that have a similar structure.
i.e if we also had
class Employee
{
public string id;
public int age;
}
public List<Employee> employees = new List<Employee>();
// Add some items to the list
It would be really cool to use the same defined Predicate, but on this list of a totally different type. Ie something like
// psudo
Predicate<T, string> predicate = return <T>.id == id;
and it work because T is always of a type that has a string member called id
I Hope that all makes sense.
I understand how I would write a Predicate to find a speciic item in a list, but not a dynamic one that could be passed in.
This is where lambda expressions come in, allowing you to create an instance of a delegate type that capture variables in scope. For example:
public Predicate<Product> CreateProductPredicateForId(string id)
{
return product => product.id == id;
}
Now in terms of making that generic, you'd need to have an interface that specifies an Id property. You can then write a generic method. For example:
public interface IEntity
{
string Id { get; }
}
...
public Predicate<T> CreatePredicateForId<T>(string id) where T : IEntity
{
return entity => entity.Id == id;
}
(note: throughout this I'm using Func<T, bool> - but the exact same logic applies to Predicate<T> - they have the equivalent signature, but you tend to see more of the former than the latter these days; that said: List<T> uses the latter)
Generics supports this, but via variance rules; you would have to declare an interface of the form:
interface IHazId
{
int Id { get; }
}
class Foo : IHazId // your types need to implement it, too!
{
public int Id { get; set; }
}
and then you can use it in a general way:
void SomeCallingCode()
{
// get the predicate, however
int id = 42;
Func<IHazId, bool> predicate = obj => obj.Id == id;
// use it
SomeTypeSpecificMethod(predicate);
}
void SomeTypeSpecificMethod(Func<Foo, bool> predicate)
=> throw new NotImplementedException("not shown");
with the compiler/runtime allowing the Func<IFoo, bool> to satisfy a type-specific Func<Foo, bool> requirement, because it knows that all Foo are IHazId. You can also do this with generics with a constraint:
void SomeCallingCode()
{
// get the predicate, however
int id = 42;
Func<IHazId, bool> predicate = obj => obj.Id == id;
// use it
SomeGenericMethod<Foo>(predicate);
}
void SomeGenericMethod<T>(Func<T, bool> predicate)
where T : IHazId
=> throw new NotImplementedException("not shown");
However, in reality, this is rarely useful, since in most cases you already know the types, and just want to do:
int id = 42;
SomeTypeSpecificMethod(x => x.Id == id);
Note also that the variance rules that allow you to treat Func<IHazId, bool> as Func<SomeType, bool> only work for reference type SomeType - which is to say: class, not struct.
Product GetProductByID(string id)
{
foreach (Product p in products)
{
if (p.id == id)
{
return p;
}
}
}
this could be replaced with
products.FirstOrDefault(p => p.Id == id)
The second part of you question could be easilly solved with inheritance, like
public class ProductA
{
public string Id { get; set; }
}
public class ProductB : ProductA
{
}
List<ProductA> a = new List<ProductA>();
List<ProductB> b = new List<ProductB>();
Func<ProductA, bool> findFunction = (p) => p.Id == id;
var p = a.FirstOrDefault(findFunction);
p = b.FirstOrDefault(findFunction);
You could use LINQ
Product myProduct = products.Where(p => p.Id == id).FirstOrDefault();
You need using System.Linq; on top of your file to use it.

Abstracting LINQ order query to multi level sort function

I would like to make a sorting extension method which will take a Generic Collection and sort it using one or more keys. The keys will be properties of the collection's containing objects.
A sample LINQ query with 3 keys looks like this.
studentResults.OrderBy(x => x.CG).ThenBy(x => x.Student.Roll)
.ThenBy(x => x.Student.Name).ToList();
I have already found something which can do this with one key.
public static List<TSource> OrderByAsListOrNull<TSource, TKey>(
this ICollection<TSource> collection, Func<TSource,TKey> keySelector)
{
if (collection != null && collection.Count > 0) {
return collection
.OrderBy(x => keySelector(x))
.ToList();
}
return null;
}
I thought of using IEnumerable<Func<TSource, TKey> keySelector>, but I cannot call the function like that.
So, how may I implement a method of this kind?
In theory, you could build a multi-levelled sort extension, which diffentiates between the initial OrderBy and the subsequent ThenBys for secondary, tertiary sorting tiebreakers. Since by taking multiple order functions, each of which could reference a different type, you'll need to soften the projected type (I've used object, below).
public static class Extensions
{
public static IEnumerable<T> MyOrderBy<T>(
this IEnumerable<T> source,
params Func<T, object>[] orders)
{
Debug.Assert(orders.Length > 0);
var sortQuery = source.OrderBy(orders[0]);
foreach(var order in orders.Skip(1))
{
sortQuery = sortQuery.ThenBy(order);
}
return sortQuery;
}
}
public class Poco
{
public string Name {get; set;}
public int Number {get; set;}
}
void Main()
{
var items = new []{
new Poco{Name = "Zebra", Number = 99},
new Poco{Name = "Apple", Number = 123}};
foreach(var poco in items.MyOrderBy(i => i.Number, i => i.Name))
{
Console.WriteLine(poco.Name);
}
}
The problem with this (as with your original function) is that you'll probably want to order by descending at some point. Although for numeric sort functions this could be hacked by passing a *-1, it's going to be really difficult to do this for an arbitrary type
// Hack : Order a numeric descending
item => item.Number * -1
For me, I would just stay with Linq's sorting extensions, and not try to abstract them in any way!

Searching for records in several tables using EF TPT

I have a project with TPT inheritance mapping, now I need to add it a search functionality that will find records in several tables. That's what I currently have:
public abstract class Customer
{
public int Id { get; set; }
public string Memo { get; set; }
...
}
public class Person : Customer
{
public string GivenName { get; set; }
public string Surname { get; set; }
...
}
public class Company : Customer
{
public string Name { get; set; }
...
}
I also have a unit of work with bunch of repositories, and I need to add the filtering functionality to several methods of CustomerRepository. Let's say I have a Count method with the following signature
public int Count(System.Linq.Expressions.Expression<Func<Customer, bool>> filter = null)
Now I need to get the quantity of customers whose GiveName or Surname contains searchTerm in case the customer is a Person or the same searchTerm in Name field in case it is a Company.
TL;DR
How a view with a single, searchable, paged list of Customers (containing both Person and Company types) should be implemented? I mean in terms of method with signature like public IHttpActionResult Get(string searchTerm, int pageSize, int pageNumber)...
That's what I tried:
I added to each of the classes a static method that would generate an Expression to search that specific class, that's how it looks for the Person class:
public static System.Linq.Expressions.Expression<Func<Person, bool>> GetFilter(string searchTerm)
{
if (String.IsNullOrWhiteSpace(searchTerm))
{
return null;
}
var parameterExpression = System.Linq.Expressions.Expression.Parameter(typeof(Person));
System.Reflection.MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
return System.Linq.Expressions.Expression.Lambda<Func<Person, bool>>(
System.Linq.Expressions.Expression.OrElse(
System.Linq.Expressions.Expression.Call(
System.Linq.Expressions.Expression.PropertyOrField(parameterExpression, "GivenName"),
method,
System.Linq.Expressions.Expression.Constant(searchTerm, typeof(string))
),
System.Linq.Expressions.Expression.Call(
System.Linq.Expressions.Expression.PropertyOrField(parameterExpression, "Surname"),
method,
System.Linq.Expressions.Expression.Constant(searchTerm, typeof(string))
)
), parameterExpression);
}
And tried to build an Expression that would check the type of the customer and then make an appropriate data check, but here I stumped... That's what I have right now:
var parameterExpression = System.Linq.Expressions.Expression.Parameter(typeof(Customer));
var typeIsPerson = System.Linq.Expressions.Expression.TypeIs(parameterExpression, typeof(Person));
var typeIsCompany = System.Linq.Expressions.Expression.TypeIs(parameterExpression, typeof(Company));
var q = System.Linq.Expressions.Expression.Block(
System.Linq.Expressions.Expression.IfThen(typeIsPerson, Person.GetFilter(searchTerm)),
System.Linq.Expressions.Expression.IfThen(typeIsCompany, Company.GetFilter(searchTerm)),
System.Linq.Expressions.Expression.Constant(false));
var a = System.Linq.Expressions.Expression.Lambda<Func<Customer, bool>>(
q, parameterExpression);
Here I have two problems(at least?), first when I try to call Count, I get a very unpleasant NotSupportedException exception that says Unknown LINQ expression of type 'Block'. The second is that I don't know how to return the result of execution for each of GetFilters, I suspect that I will get false for any record since it is default value that is the last Expression in my Block...
May be I'm on a wrong track and this is something that should be done in a completely different manner?
Expression blocks are generally unsupported in LINQ to Entities. And normally you don't need them because you could build almost any expression just using C# conditional operator ? : (which maps to Expression.Condition).
But before even trying to build an expression dynamically, you need to find a EF supported construct working with TPT (and other EF inheritance models) polymorphic query. Which is not so easy because all the examples use OfType method which is only applicable when you need to filter a concrete derived entities. With some trial and error, luckily there are two supported constructs - is and as (important: as, not cast!).
So the statically built predicate expression in question could be like this:
Expression<Func<Customer, bool>> predicate = c =>
c is Person ?
((c as Person).GivenName.Contains(searchTerm) || (c as Person).Surname.Contains(searchTerm)) :
c is Company ?
(c as Company).Name.Contains(searchTerm) :
false;
(Frankly you don't want to look at the generated SQL, but it works)
Now you can build it dynamically if you wish. You already found the is expression method (Expression.TypeIs), for as operator the corresponding expression metod is Expression.TypeAs.
You do not need to do all that. Just create a generic method that you will close when you call it. Your generic method can be like this:
public static int Count<T>(Expression<Func<T, bool>> filter = null)
{
var ctx = new StackContext();
return ctx.Customers.OfType<T>().Where(filter).Count();
}
You can call that like this:
// Here you are closing the generic to be of type Person
var personsCount = Count<Person>(x => x.GivenName == "George");
// Here you are closing the generic to be of type Customer
var companyCount = Count<Company>(x => x.Name == "Test");

Find matching element in list using delegate and lambda

Edit
My original question was not very clear, so I'd like to try to rephrase it now. Please let me know if I still miss the mark.
Essentially, I'm trying to return a new string, in which all substrings enclosed by brackets have been replaced by a string from an object in a list. As an abstract example, I want to do something like the following:
public class MyType () : IEquatable <Property>
{
public string id;
public override String ToString()
{
return id;
}
public bool Equals ( MyType other )
{
if ( other is MyType == false )
{
return false;
}
return this.id == other.id;
}
}
List<MyType> listOfCustomTypes = new List<MyType> ();
return Regex.Replace ( originalString, "{(.*?)}", d => listOfCustomTypes.Where ( t => t.id == d.Groups[1].Value ).FirstOrDefault ());
The problem I've run into, or, error, specifically, is Cannot convert lambda expression to delegate type (System.Text.RegularExpressions.MatchEvaluator) because some of the return types in the block are not implicitly convertible to the delegate return type.
I am assuming that it isn't allowed to use return types in delegates, or something, because I can normally access it's properties, or cast to string.
I've probably still managed to jumble my question, so if it helps, my full project can be seen here, and the relevant file for this question is here (specific line is 161).
Original Question
I'm trying to learn how to use delegates and lambdas, and in typical fashion, bit off more than I can chew. In the following code snippet, I define a class, which holds a list of classes. In another function, I'm trying to use a string to find a list item, and get a value from that item.
[XmlRoot ( "Replacers" )]
public class Replacers
{
[XmlElement ( "Property" )]
public List<Property> properties = new List<Property> ();
[XmlIgnore]
public static Replacers replacers;
}
public class Property : IEquatable <Property>
{
[XmlAttribute ( "id" )]
public string id;
[XmlElement ( "Value" )]
public List<Value> propertyValue = new List<Value> ();
public override String ToString()
{
return id;
}
public bool Equals ( Property other )
{
return this.id == other.id && this.propertyValue == other.propertyValue;
}
}
public static class GetVariable
{
public static string FromUser ( string originalString )
{
try
{
//return Regex.Replace ( originalString, "{(.*?)}", m => Replacers.replacers.properties.FindIndex ( m.Groups[1].Value ) );
} catch ( Exception e )
{
return "ERROR: Unable to find '" + Regex.Match ( originalString, "{(.*?)}" ) + "'";
}
}
}
The commented out line above is that I'm trying to figure out. How do I replace anything that matches the pattern {(.*?)} with a value from the list item of the same name.
Thanks for taking the time to consider my question!
TL;DR:
How do I iterate over a list using lambda, where the iteration returns the actual list item? As an example, I want to do something like: Regex.Replace ( input, pattern, m => myList.Where(listItem.identifier == m). I don't feel like I've made my question very clear, so please ask, if you're confused. Thank you!
Consider this example:
var foos = new[] { "aaa", "aba", "aca" };
var bars = foos.Where(f => f.Contains("b")).Select(f => Regex.Replace(f, "b", "d"));
foreach (var bar in bars)
Console.WriteLine(bar);
// Output:
ada
Edit: I'll try to address your comment
A lambda is just a shorthand for a delegate (a typed-method).
You're probably accustomed to types like int, string, double, Animal, etc.
Well, just extend that notion to method signatures.
You can think of any method signature as being a type.
Here's a method that returns a bool, and takes an int as a parameter:
bool A(int i) { ... }
So the signature can be viewed as a type.
A lambda is a shorthand for this. Here's a lambda, that takes an int, and returns a bool, just like the method signature above:
(x) => x % 2 == 0
Linq extension methods (Where(), Select(), etc) all take some delegate type, or lambda expression.
myCollection.Where(x => x % 2 == 0).Where(x => x > 10).Select(x => x * 2);
The beauty is you can keep chaining these extension methods, each one becoming an additional filter if you will.
Select() is special because it's a projection operation (it transforms the items in the collection). You can see it takes this odd parameter here:
Func<string, string> // or something like that, depends on the types in your collection
A Func is kinda like a delegate, but in a more generic sense. It's easy to understand. The first type arguments are the input parameters (think parameters of a method), and the last is the output (think the return type of a method)
Func<in, in, in, out>
Consider this:
// Here's a method signature
bool MyMethod(int a, int b)
// Here's a lambda of the same delegate type
(a, b) => a == b
// Here's a Func being assigned that lambda
Func<int, int, bool> func = (a, b) => a == b;

How to store Linq where condition in property

I'd like to know the most maintainable way (if exists) to store an entity condition in a parameter so to reuse it in every linq where conditions.
Suppose to have a Product entity:
public class Product
{
public bool IsDiscontinued { get; set; }
public int UnitsInStock { get; set; }
}
I'd like to add to the Product class a property IsOnSale that contains the logic to determine whether the product is on sale or not.
In this simple example the logic could be:
IsOnSale = IsDiscontinued == false && UnitsInStock > 0
Then I should be able to write a linq query of this type:
from p in context.Products
where p.IsOnSale == true
select p
The purpose of the solution should be that, if in the future the logic to determine whether the product is on sale or not changes (e.g. adding a property IsBackOrderAllowed), I don't have to edit the linq queries everywhere but simply have to change the IsOnSale property.
A similar question has been posted here but seems to address a more specific problem.
You could make a method that returns an IQueryable filtered by your conditions:
public IQueryable<Product> WhereOnSale(this IQueryable<Product> source)
{
return source.Where(p => p.IsDiscontinued == false && p.UnitsInStock > 0);
}
and you would use it like this:
from p in context.Products.WhereOnSale()
select p
If you want to do it with an expression like in Yakimych's answer then this would work:
Expression<Func<Product, bool>> isOnSale =
(p => p.IsDiscontinued == false && p.UnitsInStock > 0);
and you could use it like so:
context.Products.Where(isOnSale)
It is important that it is declared as an expression, otherwise Entity Framework won't be able to translate it into SQL because the lambda will be compiled into IL instead of an Expression Tree.
You can do something like this:
Func<Product, bool> isOnSaleFunc =
(p => p.IsDiscontinued == false && p.UnitsInStock > 0);
Then in your query you do:
context.Products.Where(isOnSaleFunc)
Update
As a result of the comment-discussion with #DoctaJonez - the filtering with such an approach will be performed on the client-side (which is or course inefficient), thus Expression<Func<Product, bool>> should be used instead of Func<Product,bool>.
First problem here is that linq to entities cannot work with properties which are not part of the model (= it can't work with custom properties).
You must define expression. If you define only Func it will be executed as Linq to objects:
public class Product
{
...
public static Expression<Func<Product, bool>> IsOnSale
{
get
{
return p => (p.IsDiscontinued == false && p.UnitsInStock > 0);
}
}
}
Now you must call the query this way:
var query = context.Products.Where(Product.IsOnSale);
Another approach is using model defined function.
I think you are looking for the Specification Pattern.
An article on using it with EF that includes a base implementation is available at http://huyrua.wordpress.com/2010/07/13/entity-framework-4-poco-repository-and-specification-pattern/ .
An example of how to implement this would be to make your query
from p in context.Products
where ProductSpecifications.IsOnSale.Predicate
select p
and to use the following helper and specification definition.
public static class ProductSpecifications{
public static readonly Specification<Product> IsOnSale = new Specification<Product>(x => !x.IsDiscontinued && x.UnitsInStock > 0);
}
public class Specification<TEntity> : ISpecification<TEntity>
{
public Specification(Expression<Func<TEntity, bool>> predicate)
{
_predicate = predicate;
}
public bool IsSatisfiedBy(TEntity entity)
{
return _predicate.Compile().Invoke(entity);
}
private Expression<Func<TEntity, bool>> _predicate;
public Expression<Func<TEntity,bool>> Predicate{
get{ return _predicate; }
}
}
You can do a lot more with this pattern too, so I suggest looking into it!

Categories