I am implementing a repository pattern Query class and testing using NSubstitute.
Repository interface:
public interface IMyRepository
{
IQueryable<T> Query<T>(Expression<Func<T, bool>> filter) where T : class;
}
DateTimeProvider interface:
public interface IMyDateTimeProvider
{
DateTime GetDateNow();
}
Application interface:
public interface IMyApplication
{
List<Thing> GetThingsByQuery(int status);
}
Application implementation:
public class MyApplication : IMyApplication
{
private readonly IMyRepository myRepository;
private readonly IMyDateTimeProvider myDateTimeProvider;
public MyApplication(IMyRepository myRepository, IMyDateTimeProvider myDateTimeProvider)
{
this.myRepository = myRepository;
this.myDateTimeProvider = myDateTimeProvider;
}
public List<Thing> GetThingsByQuery(int status)
{
var createdDate = this.myDateTimeProvider.GetDateNow();
return this.myRepository.Query<Thing>(t => t.CreatedDate == createdDate && t.Status == status).ToList();
}
}
Test:
[TestClass]
public class ApplicationTest
{
private IMyApplication myApplication;
private IMyDateTimeProvider myDateTimeProvider;
private IMyRepository myRepository;
[TestMethod]
public void QueriesRepository()
{
// Arrange
var createdDate = new DateTime(2014, 1, 1);
this.myDateTimeProvider.GetDateNow().Returns(createdDate);
const int Status = 1;
// Act
this.myApplication.GetThingsByQuery(Status);
// Assert
this.myRepository.Received().Query<Thing>(t => t.CreatedDate == createdDate && t.Status == Status);
}
[TestInitialize]
public void TestInitialize()
{
this.myRepository = Substitute.For<IMyRepository>();
this.myDateTimeProvider = Substitute.For<IMyDateTimeProvider>();
this.myApplication = new MyApplication(this.myRepository, this.myDateTimeProvider);
}
}
But the test fails with the following message:
NSubstitute.Exceptions.ReceivedCallsException: Expected to receive a call matching:
Query<Thing>(t => ((t.CreatedDate == value(MySolution.Test.ApplicationTest+<>c__DisplayClass0).createdDate) AndAlso (t.Status == 1)))
Actually received no matching calls.
Received 1 non-matching call (non-matching arguments indicated with '*' characters):
Query<Thing>(*t => ((t.CreatedDate == value(MySolution.Application.MyApplication+<>c__DisplayClass0).createdDate) AndAlso (t.Status == value(MySolution.Application.MyApplication+<>c__DisplayClass0).status))*)
The DateTime and Status are being parsed into value() which are different between the Application and the Test.
Why is this? How can I fix this?
For complicate expressions if often find it easier to assert on captured arguments by using callbacks than with Received(). An (incomplete) example:
Expression<Func<Thing, bool>> receivedFilter receivedFilter = null;
myRepository.When(x => x.Query<Thing>(Arg.Any<...>))
.Do(x => receivedQuery = x.Arg<Expression<Func<Thing, bool>>>());
Then, assert on the captured filter expression. It might actually simpler to just execute the expression's filter func (see e.g. here)
Func<Thing, bool> predicate = receivedFilter.Compile();
var matchingThing = new Thing
{ CreatedDate = createdData, Status = Status };
// assert matching
predicate(matchingThing).Should().BeTrue();
// assert non.matching
predicate(nonMatchingThing).Should().BeFalse();
This approach seems to make the test a little more black-boxed but this is in general not a bad thing.
The default equality comparer for an Expression is being used (referential equality):
eg, the expression (t => t.CreatedDate == createdDate && t.Status == Status``) in:
this.myRepository.Received().Query<Thing>(t => t.CreatedDate == createdDate
&& t.Status == Status );
Is a different instance to the expression in:
return this.myRepository.Query<Thing>(t => t.CreatedDate == createdDate
&& t.Status == status ).ToList();
To fix validate this method call check out argument matchers within NSubstitute.
But as an example:
Func<Expression<Thing, bool>, bool> validator =
// TODO this needs to be written properly, based on the expression,
// not its string representation
e => e.Body.ToString() == "t.CreatedDate == createdDate
&& t.Status == Status";
this.myRepository.Received().Query<Thing>(Arg.Is<Expression<Thing, bool>>(validator));
Related
Scenario :
My multitenant project is based on ASPNetBoilerPlate.
I have a "WORK" entity which is IMayHaveTenant. Every tenant must see default Works which is in HOST And also His Works too every where. How I must do that?
I need some codes like : tenantId == id || tenantId is null
Wrong Answer :
using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.MayHaveTenant)){ }
This returns other tenants Works too.
Create an interface, inherit IMayHaveTenant if you want the other built-in features that are for it:
public interface IMayHaveTenantSharedWithHost : IMayHaveTenant
{
}
Implement that interface:
public class Work : Entity, IMayHaveTenantSharedWithHost
{
public int? TenantId { get; set; }
// ...
}
Override CreateFilterExpression in your AbpDbContext subclass and handle that interface:
protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
where TEntity : class
{
Expression<Func<TEntity, bool>> expression = null;
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> softDeleteFilter = e => !IsSoftDeleteFilterEnabled || !((ISoftDelete) e).IsDeleted;
expression = expression == null ? softDeleteFilter : CombineExpressions(expression, softDeleteFilter);
}
// if (typeof(IMayHaveTenant).IsAssignableFrom(typeof(TEntity)))
if (typeof(IMayHaveTenantSharedWithHost).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> mayHaveTenantFilter = e => !IsMayHaveTenantFilterEnabled || ((IMayHaveTenant)e).TenantId == CurrentTenantId || ((IMayHaveTenant)e).TenantId == null;
expression = expression == null ? mayHaveTenantFilter : CombineExpressions(expression, mayHaveTenantFilter);
}
else if (typeof(IMayHaveTenant).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> mayHaveTenantFilter = e => !IsMayHaveTenantFilterEnabled || ((IMayHaveTenant)e).TenantId == CurrentTenantId;
expression = expression == null ? mayHaveTenantFilter : CombineExpressions(expression, mayHaveTenantFilter);
}
if (typeof(IMustHaveTenant).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> mustHaveTenantFilter = e => !IsMustHaveTenantFilterEnabled || ((IMustHaveTenant)e).TenantId == CurrentTenantId;
expression = expression == null ? mustHaveTenantFilter : CombineExpressions(expression, mustHaveTenantFilter);
}
return expression;
}
I want to query a list by Linq but filter by an other list containing two elements ( Name, Status) in my example.
This is inspired by an old question I've adapted to my issue.
LINQ: "contains" and a Lambda query
(in this answer it's working for only one element i.e. Status)
I try to use the "contains" method but didn't succeed to filter my list.
I should obtain a result with only two buildings (two, five)
Has anyone an idea where I'm stopped ?
Thanks
Blockquote
public class Building
{
public enum StatusType
{
open,
closed,
weird,
};
public string Name { get; set; }
public StatusType Status { get; set; }
}
private static readonly List<Building> BuildingList = new List<Building>()
{
new Building() {Name = "one", Status = Building.StatusType.open},
new Building() {Name = "two", Status = Building.StatusType.closed},
new Building() {Name = "three", Status = Building.StatusType.weird},
new Building() {Name = "four", Status = Building.StatusType.open},
new Building() {Name = "five", Status = Building.StatusType.closed},
new Building() {Name = "six", Status = Building.StatusType.weird},
};
private void GetResult()
{
var buildingSelect = new List<Building>
{
new Building() {Name = "two", Status = Building.StatusType.closed},
new Building() {Name = "five", Status = Building.StatusType.closed}
};
var q = (from building in BuildingList
where buildingSelect.Contains(building.Name, building.Status)
select building).ToList();
dataGridView1.DataSource = q;
}
The main problem of your LINQ is that you are trying the compare the equality of two Buildings, which LINQ can only compare by their references because Building does not implement IEquatable<Building> nor override object.Equals.
One way to solve it is to manually specify which properties to compare for equality as per #Wayne's answer.
The other way is, if Building instances are meant to be equated by their values and not by their references, implement IEquatable<Building> and override object.Equals:
public class Building : IEquatable<Building>
{
public Building(string name, StatusType status)
{
Name = name;
Status = status;
}
public enum StatusType
{
open,
closed,
weird,
};
public string Name { get; }
public StatusType Status { get; }
public static bool operator ==(Building left, Building right)
=> Equals(left, right);
public static bool operator !=(Building left, Building right)
=> !Equals(left, right);
public override bool Equals(object obj) => Equals(obj as Building);
public bool Equals(Building other)
{
if (ReferenceEquals(this, other))
{
return true;
}
if (ReferenceEquals(other, null) || GetType() != other.GetType())
{
return false;
}
return Name == other.Name && Status == other.Status;
}
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + Name?.GetHashCode() ?? 0;
hash = hash * 23 + Status.GetHashCode();
return hash;
}
}
}
That way, your original code would work because List.Contains will now use your implementation of IEquatable<Building> to check for equality.
You mean something like this?
var q = from b in BuildingList
from bs in buildingSelect
where b.Name == bs.Name && b.Status == bs.Status
select b;
or perhaps:
var q = from b in BuildingList
join bs in buildingSelect
on new { b.Name, b.Status } equals new { bs.Name, bs.Status }
select b;
You can either override the equality in the class itself, IF this makes sense.
Or just make the check normally with Any(), like this:
var q = (from building in BuildingList
where buildingSelect.Any(b => b.Name == building.Name
&& b.Status == building.Status)
select building).ToList();
I have a type which has a default sort order as it implements IComparable<T> and IComparable. I'm not getting the results I expect from LINQ , basically it looks as if the IComparable<T> which the type implements is not being applied.
I thought I would get the result I want with an expression in the form:
var result = MyEnumerable<T>.OrderBy(r => r);
where T itself implements IComparable<T>. It's not happening.
I can see related questions where specific IComparable<T> classes are specified for the sort, but I can't find one which uses the default IComparable<T> implemented by T itself.
My syntax is clearly incorrect. What is the correct syntax please?
Thanks in advance.
OrderBy uses the default comparer Comparer<T>.Default which in turn will default to use the IComparable<T> implementation for T, or the non-generic IComparable if the former does not exist.
This code works:
public class Program
{
static void Main(string[] args)
{
var list = new List<Stuff>
{
new Stuff("one"),
new Stuff("two"),
new Stuff("three"),
new Stuff("four")
};
var sorted = list.OrderBy(x => x);
foreach (var stuff in sorted)
{
Console.Out.WriteLine(stuff.Name);
}
}
}
public class Stuff : IComparable<Stuff>
{
public string Name { get; set; }
public Stuff(string name)
{
Name = name;
}
public int CompareTo(Stuff other)
{
return String.CompareOrdinal(Name, other.Name);
}
}
public static class GenericSorter
{
public static IOrderedEnumerable<T> Sort<T>(IEnumerable<T> toSort, Dictionary<string, SortingOrder> sortOptions)
{
IOrderedEnumerable<T> orderedList = null;
foreach (KeyValuePair<string, SortingOrder> entry in sortOptions)
{
if (orderedList != null)
{
if (entry.Value == SortingOrder.Ascending)
{
orderedList = orderedList.ApplyOrder<T>(entry.Key, "ThenBy");
}
else
{
orderedList = orderedList.ApplyOrder<T>(entry.Key, "ThenByDescending");
}
}
else
{
if (entry.Value == SortingOrder.Ascending)
{
orderedList = toSort.ApplyOrder<T>(entry.Key, "OrderBy");
}
else
{
orderedList = toSort.ApplyOrder<T>(entry.Key, "OrderByDescending");
}
}
}
return orderedList;
}
private static IOrderedEnumerable<T> ApplyOrder<T>(this IEnumerable<T> source, string property, string methodName)
{
ParameterExpression param = Expression.Parameter(typeof(T), "x");
Expression expr = param;
foreach (string prop in property.Split('.'))
{
expr = Expression.PropertyOrField(expr, prop);
}
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), expr.Type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, param);
MethodInfo mi = typeof(Enumerable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), expr.Type);
return (IOrderedEnumerable<T>)mi.Invoke(null, new object[] { source, lambda.Compile() });
}
}
I have this list of type IEnumerable<MyBaseType> for which I am trying to create an extra where-clause to retrieve a specific item in the list. The specific value does only exist on subtype MyFirstType and MySecondType. Not on MyBaseType.
Is it possible to create an expression kind of...
MyList.Where(b => (b is MyFirstType || (b is MySecondType)) && b.SpecificValue == message.SpecificValue);
Above is not working since b is of type MyBaseType and SpecificValue does not exist there. Also note that I do have another subtype MyThirdType that neither has the SpecificValue.
What does work doing what I want is this...
foreach (dynamic u in MyList)
{
if (u is MyFirstType || u is MySecondType)
{
if (u.SpecificValue == message.SpecificValue)
{
//Extracted code goes here
break;
}
}
}
Anyone have an idea how to create an linq expression for the above scenario?
Maybe there is a better solution but as I see it, this could work well enough... If you don't mind performance.
Well then, start by declaring an interface:
public interface IMySpecialType
{
object SpecificValue {get; set;} //you didn't specify what type this is
//all your other relevant properties which first and second types have in common
}
Then, make MyFirstType and MySecondType derive from this interface:
public class MyFirstType : MyBaseType, IMySpecialType
{
//snipet
}
public class MyFirstType : MySecondType, IMySpecialType
{
//snipet
}
Then, filter and cast:
MyList
.Where(b => (b is MyFirstType) || (b is MySecondType))
.Cast<IMySpecialType>()
.Where(b => b.SpecificValue == message.SpecificValue);
//do something
The direct translation of your code to a Linq where clause is
string messageValue = "foo";
var result = baseList.Where(item =>
{
dynamic c = item;
if(item is MyFirstType || item is MySecondType)
{
if( c.SpecificValue == messageValue)
return true;
}
return false;
});
This will require testing the type of the class though and using dynamic - so you might as well cast item to either MyFirstType or MySecondType directly.
An alternative would be using reflection to check if the property exists, using this approach you are not dependent on the actual types of your items as long as they do have the property you are interested in:
string messageValue = "foo";
var result = baseList.Where( item =>
{
var prop = item.GetType().GetProperty("SpecificValue");
if (prop != null && prop.GetValue(item, null) == messageValue)
return true;
else return false;
});
If modifying the class hierarchy is an option you can have you MyFirstType or MySecondType implement an interface that holds the property, then you can use OfType() in your Linq query:
interface ISpecific
{
string SpecificValue { get; set; }
}
class MyFirstType : MyBase, ISpecific
{
public string SpecificValue { get; set; }
}
...
string messageValue = "foo";
var result = baseList.OfType<ISpecific>()
.Where(item => item.SpecificValue == messageValue);
A far more easy way to do that would be to create an interface to mark all your classes having this property SpecificValue. Then it's a child play :
static void Main(string[] args)
{
List<MyBaseType> MyList = new List<MyBaseType>();
ISpecificValue message = new MyFirstType();
MyList.OfType<ISpecificValue>().Where(b => b.SpecificValue == message.SpecificValue);
}
}
class MyBaseType { }
interface ISpecificValue { string SpecificValue { get; set; } }
class MyFirstType : MyBaseType, ISpecificValue
{
public string SpecificValue;
}
class MySecondType : MyBaseType, ISpecificValue
{
public string SpecificValue;
}
Operator overloading is working perfect in C# code, since I am trying in the following way.
**
public class HostCode
{
public string Code { get; set; }
public string Name { get; set; }
public static bool operator ==(HostCode hc1, HostCode hc2)
{
return hc1.Code == hc2.Code;
}
public static bool operator !=(HostCode hc1, HostCode hc2)
{
return true;
}
}**
I have a clas called HostCode and it contains 2 overloading methods (one for '==' and another for '!=')
And I created a collection of Host Codes below.
**var hostCodes = new List<HostCode>()
{
new HostCode(){ Code = "1", Name = "sreekanth" },
new HostCode(){ Code = "2", Name = "sajan" },
new HostCode(){ Code = "3", Name = "mathew" },
new HostCode(){ Code = "4", Name = "sachin" }
};**
***var hc = new HostCode() { Code = "1", Name = "sreekanth" };***
***var isEq = hostCodes[1] == hc;***
when I am trying like above, the respective operator method fired in HostCode class (in this case it is '=='). So that I can write my custom logic there.
But if Iam trying with a Linq query as below, it is not firing. But in this case also Iam comparing 2 objects having same type.
**var isEqual = from obj in hostCodes where (HostCode)obj == (HostCode)hc select obj;**
Can anyone please help me to find out a way which I can compare 2 objects by Linq queries?
You can use IEqualityComparer or override equals for this purpose.
public class HostCode
{
....
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
return obj as HostCode == null ? false : (obj as HostCode).Code == Code;
}
}
And IEqualityComparer usage is when you have some equality on object and in some functions like Contain, ... you want use some specific equality:
public class EqualityComparer : IEqualityComparer<HostCode >
{
public bool Equals(HostCode x, HostCode y)
{
return y.ID == x.ID;
}
public int GetHashCode(string obj)
{
return obj.GetHashCode();
}
}
Since your question is "how should I compare them for this to work" I would answer "you should overload and use .Equals() instead of =="
And what's with your overload definition of !=?