0

I have this:

public void AssertReadWorks<T>(
    IRepository<T> repository, 
    T entity, 
    Expression<Func<T, T, bool>> keyComparer) where T : class
{
    entity = repository.GetAll().Single(x => x.Id == entity.Id);
}

[TestMethod]
public void ReadTest_DataFieldGroup()
{
    AssertReadWorks(
            _unitOfWork.DataFieldSetRepository, 
            new DataFieldSet { Label = "test", Title = "test" }, 
            (a, b) => a.Id == b.Id);
}

This does not compile since it is not known that T has an Id property. Note that the keyComparer parameter is not used at the moment. I want to use the keyComparer parameter (or another appropriate parameter) to dynamically generate the predicate for Single():

Expression<Func<T, bool>> keyComparingPredicate = 
    x => a predicate that compares the key of x with the key of `entity`;
entity = repository.GetAll().Single(keyComparingPredicate);

The point is that not all Ts will have Id properties, some will have different names, some will have composite keys. The original AssertReadWorks() works fine if it is not generic. The problem is just building the predicate dynamically in the generic case. If it can be done with something different from the keyComparer paramter, fine with me.

Any ideas? :)

pinkfloydhomer
  • 873
  • 3
  • 9
  • 16
  • I don't understand the way you're using the `entity` parameter. Since you change just the local variable, the retrieved entity won't be accessible outside of your method. I think you should make your method *return* the entity. – svick Jun 07 '13 at 10:26
  • Also, how is this different from [your previous question](http://stackoverflow.com/q/16962567/41071)? – svick Jun 07 '13 at 10:27
  • I don't need the contents of the entity outside the method. I just need to test that an entity with the same Id can be read from the repository. – pinkfloydhomer Jun 07 '13 at 10:34
  • It is different from my previous question in that this is a different approach and also a more minimal example. – pinkfloydhomer Jun 07 '13 at 10:35

2 Answers2

1

Check, if this fits for you

public T AssertReadWorks<T>(
    IRepository<T> repository,
    Func<T, bool> keyComparer)
{
    return repository.GetAll().Single(keyComparer);
}

Using

[TestMethod]
public void TestInt()
{
    var repository = new Repository<int>( new[] {1, 2, 3} );
    var intEntity = 3;
    AssertReadWorks(repository, e => e == intEntity);
}

[TestMethod]
public void TestString()
{
    var repository = new Repository<string>(new[] { "a", "b", "c" });
    var stringEntity = "A";
    AssertReadWorks(repository, e => string.Equals(e, stringEntity, StringComparison.OrdinalIgnoreCase));
}

[TestMethod]
public void TestThread()
{
    var threadEntity = new Thread(() => { });
    var repository = new Repository<Thread>(new[] { threadEntity, new Thread(() => { }), new Thread(() => { }) });
    AssertReadWorks(repository, e => e.ManagedThreadId == threadEntity.ManagedThreadId);
}

EDIT: Response for comment:

public void AssertReadWorks<T>(
    IRepository<T> repository,
    ref T entity,
    Func<T, T, bool> keyComparer)
{
    var localEntity = entity;
    entity = repository.GetAll().Single(e => keyComparer(e, localEntity));
}
FireAlkazar
  • 1,795
  • 1
  • 14
  • 27
  • That's not general enough for my purpose, I'm afraid. I want AssertReadWorks to take the entity as a parameter (for unrelated reasons), and I want to be able to just create the entity with new in the same line as my call to AssertReadWorks, as shown. – pinkfloydhomer Jun 07 '13 at 10:19
  • Sorry, I think I am able to use this after all. Thanks! – pinkfloydhomer Jun 07 '13 at 10:36
  • The only thing is that I now have to call using two lines like this: var entity = new DataFieldSet {Label = "test", Title = "test"}; AssertCrudOperationsWork(entity, x => x.Id == entity.Id, x => x.IsClosed = true); Ideally, I would like to be able to call AssertCrudOperationsWork() in one line, new'ing the entity in the same line and then also in the same line providing the means for testing the equality of keys. But this is better than nothing. – pinkfloydhomer Jun 07 '13 at 10:39
  • If I use your edited response, I have to change the keyComparer parameter at the caller to something like (a, b) => a.Id == b.Id which is fine, but then the call to Single throws this: The LINQ expression node type 'Invoke' is not supported in LINQ to Entities. – pinkfloydhomer Jun 07 '13 at 11:26
  • @pinkfloydhomer Sorry, forgot you have LINQ2Entities. Guess we have workaround for the case, but I lack knowledge to implement it. So I post my own question:))) http://stackoverflow.com/questions/16985310/convert-expressionfunct-t-bool-to-expressionfunct-bool – FireAlkazar Jun 07 '13 at 13:30
0

Correct me if I'm wrong but is the whole point of this function to check equality? To do this in a generic sense you can use IEquatable Interface. This way your objects knows how to compare themselves to the same object. This should cut down your code reuse and help avoid creating the same expression in multiple places.

So your class would look like this:

public class DataFieldSet : IEquatable<DataFieldSet>
{
    public int Id { get; set; }

    public bool Equals(DataFieldSet other)
    {
        return other != null && this.Id == other.Id;
    }
}

And your Assert function

public void AssertReadWorks<T>(
    IRepository<T> repository, 
    T entity) where T : IEquatable<T>
{
    entity = repository.GetAll().Single(x => entity.Equals(x);
}
pingoo
  • 2,074
  • 14
  • 17
  • No, the whole point is not equality. The point is to test whether reading from the database works as expected (primarily to test that our Entity Framework model maps correctly to the database). I do this by using a where clause, or predicate if you will, for Single(). In the non-generic case it just becomes .Single(x => x.Id == entity.Id) as shown. It is very simple and works. The problem is that I want a generic version. That means that I have to be able to compare the primary key (composite or otherwise, no matter the names of the key properties) of x and entity. – pinkfloydhomer Jun 07 '13 at 10:16