Linq expression where clause with generic type - linq

In my Data access layer, I am calling the GET method with the following Lambda expression :
public List<T> Get<T>() where T : class
{
var list = Context.Set<T>().ToList().Distinct().Where(x => x.Content_type == "Test");
return list;
}
But getting error
"Cannot resolve symbol Content_type"
How can i resolve this issue ?

The problem is that Content_type is not a part of T class because it's just a class.
As #tchelidze says, you can set a where clause on your function to specify a type, like this :
public List<T> Get<T>() where T : IYourCommonInterface
{
var list = Context.Set<T>().Where(x => x.Content_type == "Test").Distinct().ToList();
return list;
}
But if you need to be totaly generic, you can add a selector to your function like this :
public List<T> Get<T>(Func<T, object> selector) where T : class
{
var list = Context.Set<T>().Where(x => selector(x) == "Test").Distinct().ToList();
return list;
}
And use it like that :
Get(x => x.Content_type);
Also, if you want to go further, you can pass the entire condition :
public List<T> Get<T>(Func<T, bool> condition) where T : class
{
var list = Context.Set<T>().Where(condition).Distinct().ToList();
return list;
}
And use it like this :
Get(x => x.Content_type == "test");
Hope it helps.

Reason is that all you know about T is that it is a class. You do not know if it contains Content_type property or not.
If you always pass T class which contains definition for Content_type try following .
Context.Set<T>().ToList().Distinct().Where(x => (x as SomeClassWithContentTypeField).Content_type == "Test");
Better way will be if you introduce interface IHasContentTypeField which declared Content_type property
public interface IHasContentTypeField
{
string Content_type { get; set; }
}
then constraint T to this interface.
public List<T> Get<T>() where T : IHasContentTypeField
Then you can implement IHasContentTypeField in classes for which you want to call Get<T> method.
public class A : IHasContentTypeField
{
public string Content_type { get; set; }
}

Related

Nested validators can only be used with Member Expressions

I am trying to use fluent validation .
Looking to run validation against the IList items.
public class ProgramDetailsValidatorForBulkEdit : ValidatorCollection<IList<ProgramDTO>>
{
public ProgramDetailsValidatorForBulkEdit()
{
RuleFor(x => x).Cascade(CascadeMode.StopOnFirstFailure).SetCollectionValidator(new ProgramDetailsValidator1());
}
}
public class ProgramDetailsValidator1 : AbstractValidator<ProgramDTO>
{
public ProgramDetailsValidator1()
{
RuleFor(c => c.Capacity).NotNull()
.WithMessage(String.Format(AppConstants.ValidationTemplates.RequiredField, "Capacity"));
}
}
The error returned when calling the line is "Nested validators can only be used with Member Expressions."
RuleFor(x => x).Cascade(CascadeMode.StopOnFirstFailure).SetCollectionValidator(new ProgramDetailsValidator1());
Reason of error
Error message contains words "Member Expressions". The problem is in RuleFor(x => x). Nested validators must be used only with lambdas which select some members of x, for example, with x => x.MySubobject1. Lambda x => x does not select any member of x.
To validate the collection
Create object containing the list:
public class MyObject
{
public List<Item> Items { get; set; }
}
You can use generics to create 1 universal object and validator for it for all lists.
public class MyObjectValidator : AbstractValidator<MyObject>
{
public MyObjectValidator()
{
RuleFor(x => x.Items) // will work, because it is not "x => x"
.SetCollectionValidator(new ItemValidator());
}
}
To validate an object
Use lambdas pointing to members to validate inner objects and use inheritance from your object's validator to validate the root x.
public class MySimpleObject { ... }
public class MyCompositeObject : MySimpleObject
{
public MyType1 MySubobject1 { get; set; }
public MyType2 MySubobject2 { get; set; }
}
public class MySimpleObjectValidator : AbstractValidator<MySimpleObject>
{
public MySimpleObjectValidator()
{
...
}
}
public class MyCompositeObjectValidator : MySimpleObjectValidator
{
public MyCompositeObjectValidator () : base() // Call base validator to implement rules for "x => x" written in MySimpleObjectValidator!
{
// Rules for SUBobjects will work
RuleFor(x => x.MySubobject1)
.SetValidator(new MyType1Validator())
.WithName("Subobject1's errors group");
RuleFor(x => x.MySubobject2)
.SetValidator(new MyType2Validator())
.WithName("Subobject2's errors group");
}
}

Deleting from a generic list

I have this problem with lists and I can't seem to fix it
I have this class that implement a interface that has the following method.
public List<T> CalculateWad<T, TH>(
List<T> outputList,
List<TH> inputList,
bool flag)
{
...
}
Now, I have a outputlist and a inputlist with a common field Contract. I need to delete in outputlist all contracts that exist in inputlist.
It has to be as generic as possible. I can't seem to be able to get the fields of the lists.
Any ideas?
In order to access the Contract property, the generics T and TH must implement an interface with the Contract property.
Documentation : where (generic type constraint) (C# Reference)
interface IContractable { string Contract { get; } }
Then your class containing the CalculateWad method must be define as follow :
class MyClass<T, TH>
where T : IContractable
where TH : IContractable
{
public List<T> CalculateWad(List<T> outputList, List<TH> inputList, bool flag)
{
return outputList
.Where(o =>
inputList.Select(i => i.Contract).Contains(o.Contract) == false)
.ToList();
}
}
This should to the job, by adding a common IHasContract interface that both T and TH must implement:
class Program
{
static void Main(string[] args)
{
}
private IList<T> CalculateWad<T, TH>(IList<T> output,
IList<TH> input, bool flag)
where T : IHasContract
where TH : IHasContract
{
var contracts = new HashSet<string >(input.Select(i => i.Contract));
var qry = from o in output
where !contracts.Contains(o.Contract)
select o;
return qry.ToList();
}
private sealed class Contract
{
}
private interface IHasContract
{
string Contract { get; }
}
private sealed class Foo : IHasContract
{
public string Contract { get; set; }
}
private sealed class Bar : IHasContract
{
public string Contract { get; set; }
}
}
Note that is does not modify output, which you mention in the text. It does, however, return a new altered copy of the list, which may be rather what the method signature describes.
So this is your interface:
public List CalculateWad( List outputList, List inputList, bool flag) {
...
}
And you need to do this? Assumes that the objects in each list can be compared by their equals method.
public List<T> CalculateWad<T, TH>( List<T> outputList, List<TH> inputList, bool flag) {
// cast list to be regular object lists
List out = (List) outputList;
List in = (List) inputList;
for(Object object : in){
out.remove(object); // this looks for an object that matches using contract.equals(object)
}
}
What is flag variable for?

Returning a custom list class type from LINQ Query - return same type going in that is coming out

I have a custom List (MyCustomList) that implements List(Of MyCustomClass).
I want to run a LINQ query against that and return a filtered MyCustomList.
Public ReadOnly Property DebitTransactions As MyCustomList
Get
Return From item In Me Where item.IsDebit = True Select item
End Get
End Property
I get a type conversion here because the LinQ query doesn't return the list in the same MyCustomList that it was filtering. It cannot convert a WhereSelectListIterator object (which is returned) to a MyCustomClass.
I really need the filtered results to be in the same format they came in as. Any suggestions?
If you implement your own Where exthension method you can keep using linq syntax.
public class MyCustomList : List<MyCustomClass>
{
public MyCustomList() : base()
{
}
public MyCustomList(IEnumerable<MyCustomClass> coll) : base(coll)
{
}
}
public static class MyCustomListExtensions
{
public static MyCustomList Where(this MyCustomList myList, Func<MyCustomClass, bool> predicate)
{
return new MyCustomList(Enumerable.Where(myList, predicate));
}
}
public class MyCustomClass
{
public int Int1 { get; set; }
public string Str1 { get; set; }
}
And here I'm using the custom Where implementation:
var myList = new MyCustomList()
{
new MyCustomClass() { Int1 = 1},
new MyCustomClass() { Int1 = 2},
new MyCustomClass() { Int1 = 3},
};
MyCustomList filteredList = from item in myList where item.Int1 > 1 select item;
Assert.AreEqual(2, filteredList.Count);
You have to iterate the list, add them to a collection, and return the collection. Linq doesn't support, directly, conversion of iterators to custom return types other than List, arrays and Dictionaries.

Linq - reuse expression on child property

Not sure if what I am trying is possible or not, but I'd like to reuse a linq expression on an objects parent property.
With the given classes:
class Parent {
int Id { get; set; }
IList<Child> Children { get; set; }
string Name { get; set; }
}
class Child{
int Id { get; set; }
Parent Dad { get; set; }
string Name { get; set; }
}
If i then have a helper
Expression<Func<Parent,bool> ParentQuery() {
Expression<Func<Parent,bool> q = p => p.Name=="foo";
}
I then want to use this when querying data out for a child, along the lines of:
using(var context=new Entities.Context) {
var data=context.Child.Where(c => c.Name=="bar"
&& c.Dad.Where(ParentQuery));
}
I know I can do that on child collections:
using(var context=new Entities.Context) {
var data=context.Parent.Where(p => p.Name=="foo"
&& p.Childen.Where(childQuery));
}
but cant see any way to do this on a property that isnt a collection.
This is just a simplified example, actually the ParentQuery will be more complex and I want to avoid having this repeated in multiple places as rather than just having 2 layers I'll have closer to 5 or 6, but all of them will need to reference the parent query to ensure security.
If this isnt possible, my other thought was to somehow translate the ParentQuery expression to be of the given type so effectively:
p => p.Name=="foo";
turns into:
c => c.Dad.Name=="foo";
but using generics / some other form of query builder that allows this to retain the parent query and then just have to build a translator per child object that substitutes in the property route to the parent.
EDIT:
Following on from comments by #David morton
Initially that looks like I can just change from Expression to a delegate function and then call
.Where(ParentQuery()(c.Dad));
However I am using this in a wider repository pattern and cant see how I can use this with generics and predicate builders - I dont want to retrieve rows from the store and filter on the client (web server in this case). I have a generic get data method that takes in a base expression query. I then want to test to see if the supplied type implements ISecuredEntity and if it does append the securityQuery for the entity we are dealing with.
public static IList<T> GetData<T >(Expression<Func<T, bool>> query) {
IList<T> data=null;
var secQuery=RepositoryHelperers.GetScurityQuery<T>();
if(secQuery!=null) {
query.And(secQuery);
}
using(var context=new Entities.Context()) {
var d=context.GetGenericEntitySet<T>();
data=d.ToList();
}
return data;
}
ISecuredEntity:
public interface ISecuredEntity : IEntityBase {
Expression<Func<T, bool>> SecurityQuery<T>();
}
Example Entity:
public partial class ExampleEntity: ISecuredEntity {
public Expression<Func<T, bool>> SecurityQuery<T>() {
//get specific type expression and make generic
Type genType = typeof(Func<,>).MakeGenericType(typeof(ExampleEntity), typeof(bool));
var q = this.SecurityQuery(user);
return (Expression<Func<T, bool>>)Expression.Lambda(genType, q.Body, q.Parameters);
}
public Expression<Func<ExampleEntity, bool>> SecurityQuery() {
return e => e.OwnerId==currentUser.Id;
}
}
and repositoryHelpers:
internal static partial class RepositoryHelpers {
internal static Expression<Func<T, bool>> SecureQuery<T>() where T : new() {
var instanceOfT = new T();
if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>();
}
return null;
}
}
EDIT Here is the (eventual) solution
I ended up going back to using expressions, and using LinqKit Invoke. Note: for EF I also had to call .AsExpandable() on the entitySet
The key part is being able to call:
Product.SecureFunction(user).Invoke(pd.ParentProduct);
so that I can pass in the context into my parent query
My end classes look like:
public interface ISecureEntity {
Func<T,bool> SecureFunction<T>(UserAccount user);
}
public class Product : ISecureEntity {
public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
return SecureFunction(user) as Expression<Func<T,bool>>;
}
public static Expression<Func<Product,bool>> SecureFunction(UserAccount user) {
return f => f.OwnerId==user.AccountId;
}
public string Name { get;set; }
public string OwnerId { get;set; }
}
public class ProductDetail : ISecureEntity {
public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
return SecureFunction(user) as Expression<Func<T,bool>>;
}
public static Func<ProductDetail,bool> SecureFunction(UserAccount user) {
return pd => Product.SecureFunction(user).Invoke(pd.ParentProduct);
}
public int DetailId { get;set; }
public string DetailText { get;set; }
public Product ParentProduct { get;set; }
}
Usage:
public IList<T> GetData<T>() {
IList<T> data=null;
Expression<Func<T,bool>> query=GetSecurityQuery<T>();
using(var context=new Context()) {
var d=context.GetGenericEntitySet<T>().Where(query);
data=d.ToList();
}
return data;
}
private Expression<Func<T,bool>> GetSecurityQuery<T>() where T : new() {
var instanceOfT = new T();
if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>(GetCurrentUser());
}
return a => true; //returning a dummy query
}
}
Thanks for the help all.
You're overthinking it.
First, don't return an Expression<Func<Parent, bool>>, that'll require you to compile the expression. Return simply a Func<Parent, bool> instead.
Next, it's all in how you call it:
context.Children.Where(c => c.Name == "bar" && ParentQuery()(c.Dad));
context.Parents.Where(ParentQuery());

linq populate custom collection

I have a collection defined as:
public class MyCollection : List<MyItem>
{
...
}
public class MyItem
{
...
}
Using linq, I can use the Select method to return a IEnumerable, and I can call .ToList on that to get an IList but is there some way of getting back a type of MyCollection? Because I am tring to instantiate a class which has a property of type MyCollection, and I want to use object initialization.
For example:
public class MyClass
{
MyCollection TestCollection {get;set}
...
}
MyClass test = new MyClass()
{
...
TestCollection = SomeObject.Select(item => new MyItem()
{
...
}).ToList();
}
I get a compile error because ToList returns List and it can't cast to a MyCollection object. Is there a way to do that?
You'll need to construct your MyCollection instance with the IEnumerable<MyItem>. Add a constructor like:
public MyCollection(IEnumerable<MyItem> items) : base(items) {}
Then, when you go to use this, you can do:
TestCollection = new MyCollection(SomeObject.Select(item => new MyItem());
You could make your own extension method that builds your collection from an IEnumerable, like
public static class Extensions
{
public static MyCollection ToMyCollection(this IEnumerable<MyItem> items)
{
//build and return your collection
}
}
or if MyItem is a placeholder for generic types in your context :
public static class Extensions
{
public static MyCollection ToMyCollection<T>(this IEnumerable<T> items)
{
//build and return your collection
}
}
Just mimic ToList:
public static class MyCollectionExtensions {
public static MyCollection ToMyCollection(this IEnumerable<MyItem> source) {
if (source == null) throw new NullReferenceException();
return new MyCollection(source);
}
}
MyCollection needs a new constructor:
public class MyCollection : List<MyItem> {
public MyCollection() : base() { }
public MyCollection(IEnumerable<MyItem> source) : base(source) { }
...
}
Also, it's generally not advisable to expose a setter for a collection. You should encapsulate mutation of the collection inside the class:
public class MyClass {
public MyCollection TestCollection { get { ... } } // should return a read-only collection
public void Add(MyItem item) {
_testCollection.Add(item);
}
MyCollection _testCollection = ...;
...
}

Resources