【问题标题】:Convert Func<TDao, bool> to Func<TEntity, bool>将 Func<TDao, bool> 转换为 Func<TEntity, bool>
【发布时间】:2013-08-16 14:40:33
【问题描述】:

给定:

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

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

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

如何获取Expression&lt;Func&lt;MyDao, bool&gt;&gt; 类型的谓词参数并将其转换为Expression&lt;Func&lt;MyEntity, bool&gt;&gt;

我正在寻找的答案类型

请注意,答案必须显示转换的工作原理。我想要一个与此类似但可行的实现:)....

    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;
    }

关于我为什么想要这个设计的详细信息...

这是一个 asp.net MVC 5 应用程序。这种转换很重要的原因是我的视图不知道MyEntity 的类型。换句话说,如果我这样做:

myDaoObject.ReadSingle&lt;MyEntity&gt;(myEntity =&gt; myEntity.SiteId == "123");

然后我的视图层必须引用我的 DLL 层,因为这里我使用的是MyEntity。我希望 View 层与 Dao 一起工作:

myDaoObject.ReadSingle&lt;MyDao&gt;(myDao=&gt; myDao.SiteId == "123");

但是,现在我必须转换 Dao 以使其可用于存储库。 Repository 只知道 DL 对象。我试图避免创建冗余存储库只是为了支持这种翻译。 DAO 包含实体的所有属性以及一些属性。

【问题讨论】:

  • 你能告诉我们你调查和尝试了什么吗?
  • @Default - 问题更新为接近我需要的实现。

标签: c#


【解决方案1】:

我手头没有确切的代码,但您可能希望使用提供的表达式并自己执行等价转换。

This stackoverflow question 符合我的意愿。

P.Brian.Mackey 的说明

提到的答案有效。使用乔恩的答案就可以了。但是,答案的公共部分最终成为Func&lt;&gt; 转换的不可见参与者。我只需要:

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

请注意,此方法是私有的。我把它改成了公开的。有关完整实施,请参阅上面引用的答案中的@Jon 答案。

public static Expression<Func<TNewTarget, bool>> TransformPredicateLambda<TOldTarget, TNewTarget>(Expression<Func<TOldTarget, bool>> predicate)

【讨论】:

    【解决方案2】:

    让它们共享一个通用界面:

    public interface ISited {
        int SiteId {get; set; }
    }
    
    class MyDao : ISited { .. }
    class MyEntity : ISited { .. }
    

    并使用通用接口作为泛型类型参数的约束来代替C3VAddressDao

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

    当然,如果没有其他常见成员(您将在 ISited 中包含),这可能不会那么有用。

    【讨论】:

    • 这是个好主意,但在尝试时我发现因为我在存储库中使用了DbContext.Set&lt;TEntity&gt;(),所以我不能使用它。如果不可能,我需要在 Func 之间进行转换,或者完全做其他事情。
    • @P.Brian.Mackey,我也遇到了同样的问题,你能帮帮我吗,请检查this
    【解决方案3】:

    为什么不传进去

    public Cv3AddressDao ReadSingle<TEntity>(Expression<Func<TEntity, bool>> predicate)
    {
        // ...
    }
    ...
    var dao = new MyDao();
    var addr = dao.ReadSingle<MyEntity>(x => x.SiteId == 1);
    

    【讨论】:

    • 这将导致我的视​​图层耦合到我的数据层。道的重点是我没有这种耦合。即使进行了更新,它也需要在视图中定义兰巴。我不明白这将如何工作。
    • @P.Brian.Mackey 你没有在你的问题中提到层,也许你应该更新你的问题,以便清楚你的要求是什么。在您详细说明您的应用架构之前,很难修改我的答案。
    • 我更新了问题。希望这能解决问题。
    【解决方案4】:
        public static Expression<Func<B, bool>> MapFun<A, B>(Expression<Func<A, bool>> input) where A : class
        {
            return b => input.Compile()((b as A));
        }
    

    这应该对你有用,因为你只是在转换参数。

    更新:

    根据您更新的答案,您有几个选择。

    使用反射将值从实体复制到 DAO(查看 AutoMapper 之类的内容)

    您拥有的另一个选项是使用 IConvertable 之类的东西在您的 2 种类型之间定义自定义转换。

    【讨论】:

    • 哎呀好近...运行时错误:No coercion operator is defined between types 'System.Boolean' and 'MvcApplication1.Models.MyEntity'.
    • @P.Brian.Mackey 编辑了我的答案,基本上你想用 B 而不是 A 类型调用输入,所以你需要将 B 转换为 A,由于编译时错误而添加了约束。
    • 不同的运行时错误:The LINQ expression node type 'Invoke' is not supported in LINQ to Entities. 我突然遇到了 TFS 问题。我得先把这个放在桌子上……
    • 我从来没有处理过 LINQ to Entities,所以我不能说。我会问你为什么要编写一个期望 MyDao 的表达式,然后你调用一个将传入 MyEntity 的方法,只需编写你的表达式来期望 MyEntity。
    猜你喜欢
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多