2

Given:

class MyDao
{
   public int SiteId {get;set;}

   public Cv3AddressDao ReadSingle(Expression<Func<Cv3AddressDao, bool>> predicate)
   { //...
   }
}

class MyEntity
{
   public int SiteId {get;set;}
}

How can I take the predicate parameter of type Expression<Func<MyDao, bool>> and convert it to Expression<Func<MyEntity, bool>>?

The type of Answer I am looking for

Please note that answers must show how conversion works. I want an implementation similar to this but that works :)....

    public MyDao ReadSingle(Expression<Func<MyDao , bool>> predicate)
    {
        var mappedPredicate = MapFun<MyDao , MyEntity>(predicate);
        var result = repository.GetSingle<MyEntity>(mappedPredicate);

        return Convert(result);//Converts Entity to Dao...safe to ignore this line
    }

    Expression<Func<B, bool>> MapFun<A, B>(Expression<Func<A, bool>> input)
    {
        Expression<Func<B, bool>> result = null;//How to convert?
        return result;
    }

Details regarding why I want this design...

This is an asp.net MVC 5 application. The reason this conversion is important is so my View is not aware of the type MyEntity. In other words if I were to do:

myDaoObject.ReadSingle<MyEntity>(myEntity => myEntity.SiteId == "123");

Then my View layer has to reference my DLL layer because here I am using MyEntity. I want the View layer to work with the Dao instead:

myDaoObject.ReadSingle<MyDao>(myDao=> myDao.SiteId == "123");

But, now I have to convert the Dao to make it useable with the Repository. The Repository is only aware of DL objects. I am trying to avoid creating a redundant Repository just to support this translation. The DAO contains all the properties of the Entity plus some.

P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348

4 Answers4

3

I don't have the exact code handy, but you will probably want to consume the expression provided and perform the equivalency conversion yourself.

This stackoverflow question is along the lines of what I would do.

Note from P.Brian.Mackey

The referred to answer worked. Using Jon's answer does the trick. However, the public portion of the answer ended up being a non-visible player for Func<> conversion. All I needed was:

    Expression<Func<B, bool>> MapFun<A, B>(Expression<Func<A, bool>> input)where A : class
    {
        var result = DbAccessLayer.TransformPredicateLambda<A,B>(input);
        return result;
    }

Note that this method was private. I changed it to public. See @Jon answer in the answer referenced above for the full implementation.

public static Expression<Func<TNewTarget, bool>> TransformPredicateLambda<TOldTarget, TNewTarget>(Expression<Func<TOldTarget, bool>> predicate)
Community
  • 1
  • 1
Guvante
  • 18,775
  • 1
  • 33
  • 64
1

Have them share a common interface:

public interface ISited {
    int SiteId {get; set; }
}

class MyDao : ISited { .. }
class MyEntity : ISited { .. }

and use the common interface as a constraint on the generic type parameter in place of C3VAddressDao:

 public ISited ReadSingle(Expression<Func<ISited, bool>> predicate)

Of course, this might not be that useful without other common members that you would include in ISited.

Keith Payne
  • 3,002
  • 16
  • 30
  • This is a good idea, but in trying it I found that because I use `DbContext.Set()` in the repository I can't use this. I need to convert between Func<>'s or do something else entirely if that is not possible. – P.Brian.Mackey Aug 16 '13 at 16:12
  • @P.Brian.Mackey, I am also stuck in the same problem, can you please help me, please check [this](https://stackoverflow.com/questions/67884451/convert-expressionfunct-bool-to-another-predicate-expression-expressionfun) – Akash Kumar Jun 08 '21 at 15:14
0

Why not pass it in

public Cv3AddressDao ReadSingle<TEntity>(Expression<Func<TEntity, bool>> predicate)
{
    // ...
}
...
var dao = new MyDao();
var addr = dao.ReadSingle<MyEntity>(x => x.SiteId == 1);
James
  • 80,725
  • 18
  • 167
  • 237
  • This would result in coupling my View layer to my data layer. The point of the Dao is so I don't have this coupling. Even with the update it requires that the lamba is defined in the View. I don't see how this will work. – P.Brian.Mackey Aug 16 '13 at 14:46
  • @P.Brian.Mackey you make no mention of layers in your question, maybe you should update your question so it's *clear* what your requirements are. Until you detail your app architecture it's difficult to revise my answer. – James Aug 16 '13 at 14:57
  • I updated the question. Hopefully that will clear things up. – P.Brian.Mackey Aug 16 '13 at 15:16
0
    public static Expression<Func<B, bool>> MapFun<A, B>(Expression<Func<A, bool>> input) where A : class
    {
        return b => input.Compile()((b as A));
    }

that should work for you because you're just converting the parameter.

update:

based on your updated answer you have a couple options.

Use reflection to copy values from the entity to the DAO (look at something like AutoMapper)

the other option you have is to define a custom conversion between your 2 types using something like IConvertable.

Eluvatar
  • 2,265
  • 19
  • 24
  • Ugh so close...Runtime error: `No coercion operator is defined between types 'System.Boolean' and 'MvcApplication1.Models.MyEntity'.` – P.Brian.Mackey Aug 16 '13 at 15:28
  • @P.Brian.Mackey edited my answer, basicly you want to call input with B instead of type A, so you'll need to cast B to A, constraint added due to compile time error. – Eluvatar Aug 16 '13 at 15:38
  • Different runtime error: `The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.` I'm having TFS trouble all the sudden. Gonna have to table this for a bit... – P.Brian.Mackey Aug 16 '13 at 15:51
  • I've never dealt with LINQ to Entities so I cant say. I would ask why you're writing an expression that expects a MyDao but then you're calling a method that will pass in a MyEntity, just write your expression to expect MyEntity instead. – Eluvatar Aug 16 '13 at 15:57