有没有一种方法使用'dynamic`在lambda EX pression树? [英] Is there a way to use `dynamic` in lambda expression tree?

查看:151
本文介绍了有没有一种方法使用'dynamic`在lambda EX pression树?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,规范。我们使用MVC5,.NET 4.5.1,以及实体框架6.1。

First, spec. We use MVC5, .NET 4.5.1, and Entity framework 6.1.

在我们的MVC5的业务应用程序,我们有很多重复的CRUD code。我的工作是自动大部分,这意味着它解压到基类,并使其可重复使用。现在,我有基类控制器,视图模型和EF6实体模型。

In our MVC5 business application we have a lot of repetitive CRUD code. My job is to "automate" most of it, which means extracting it to base classes and making it reusable. Right now, I have base classes for controllers, view models and EF6 entity models.

这一切EF6实体继承我的抽象基类:

My abstract base class that all EF6 entities inherit:

public abstract class BaseEntity<TSubclass>
    where TSubclass : BaseEntity<TSubclass>
{
    public abstract Expression<Func<TSubclass, object>> UpdateCriterion();
}

UpdateCriterion 方法是用在数据库方面的 AddOrUpdate 方法。我有一个子类的通用参数,因为 UpdateCriterion 需要返回使用确切的子类型,而不是一个接口或基类的lambda EX pression。一个非常简单的子类实现这个抽象基类是这样的:

UpdateCriterion method is used in AddOrUpdate method of database context. I have a generic parameter for subclasses because UpdateCriterion needs to return lambda expression that uses exact subclass type, not an interface or base class. An extremely simplified subclass implementing this abstract base class would look like this:

public class Worker : BaseEntity<Worker>
{
    public int ID { get; set; }
    public int Name { get; set; }

    public override Expression<Func<Worker, object>> UpdateCriterion()
    {
        return worker => worker.ID;
    }
}

在此之后,在 SaveOrUpdate 我的基本控制器的动作,我会code是这样的:

After that, in SaveOrUpdate action of my base controller, I would have code like this:

public ActionResult Save(TViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        var entityModel = viewModel.ConstructEntityModel();
        db.Set<TEntityModel>().AddOrUpdate<TEntityModel>(entityModel.UpdateCriterion(), entityModel);
        db.SaveChanges();
    }
}

感谢的是,基本控制器的子类并不需要实现保存方法本身,像以前一样。现在,这一切的作品,它实际上确实很好,尽管时髦的语法(我的意思是,类BaseEntity&LT; TSubclass化合物其中TSubclass:BaseEntity&LT; TSubclass&GT; ,认真) 。

Thanks to that, subclasses of the base controller don't need to implement Save method themselves, as they did before. Now, all of this works, and it actually works really well despite the funky syntax (I mean, class BaseEntity<TSubclass> where TSubclass : BaseEntity<TSubclass>, seriously?).

下面来我的问题。对于大多数实体领域 ID 是关键,但对有些人来说是没有,所以我可以正常使用超类实现不能一概而论。因此,现在,每一个实体子类实现它自己的 UpdateCriterion 。但是,因为对于大多数(90%+)的实体 E =&GT; e.ID 是正确的执行,我有很多的重复。所以我想重写实体基类是这样的:

Here comes my problem. For most of the entities field ID is the key, but for some it isn't, so I can't generalise properly with a superclass implementation. So for now, every entity subclass implements it's own UpdateCriterion. But, since for most (90%+) entities e => e.ID is the correct implementation, I have a lot of duplication. So I want to rewrite the entity base class to something like this:

public abstract class BaseEntity<TSubclass> 
    where TSubclass : BaseEntity<TSubclass>
{
    public virtual Expression<Func<TSubclass, object>> UpdateCriterion()
    {
        return entity => ((dynamic)entity).ID;
    }
}

我们的目的是提供一种使用ID作为密钥的缺省实现,并且允许子类覆盖它,如果他们使用不同的密钥。我不能用一个接口或基类与ID字段,因为不是所有的实体拥有它。我想我会使用动态退出 ID 字段,但我得到以下错误:错误:EX pression树不能包含动态操作

The intention is to provide default implementation that uses ID as key, and allow subclasses to override it if they use a different key. I can't use an interface or a base class with ID field because not all entities have it. I thought I'd use dynamic to pull out ID field, but I get following error: Error: An expression tree may not contain a dynamic operation.

那么,如何做到这一点的任何想法?会在基地工作的反思 UpdateCriterion

So, any idea on how to do this? Would reflection work in base UpdateCriterion?

推荐答案

没有,你不能在LINQ到实体查询中使用的动态。 但你可以在运行时建立的lambda防爆pression。

No, you cannot use dynamic in a Linq to Entities query. But you can build the Lambda Expression at runtime.

public virtual Expression<Func<TSubclass, object>> UpdateCriterion()
{
    var param = Expression.Parameter(typeof(TSubclass));
    var body = Expression.Convert(Expression.Property(param, "ID"), typeof(object));

    return Expression.Lambda<Func<TSubclass, object>>(body, param);
}

如果该TSubclass类型没有一个ID属性ex pression.Property(参数,ID)会抛出异常。

If the TSubclass type does not have an ID property Expression.Property(param, "ID") will throw an exception.

此外,你可以使用MetadataWorkspace从你的实体模型,得到了主键列TSubclass。

Additionally you could use the MetadataWorkspace from your entity model to get the Primary Key column for TSubclass.

这篇关于有没有一种方法使用'dynamic`在lambda EX pression树?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆