C# 有没有在lambda表达式树中使用'dynamic'的方法?

C# 有没有在lambda表达式树中使用'dynamic'的方法?,c#,.net,linq,entity-framework,lambda,C#,.net,Linq,Entity Framework,Lambda,首先,规范。我们使用MVC5、.NET4.5.1和实体框架6.1 在我们的MVC5业务应用程序中,我们有很多重复的CRUD代码。我的工作是“自动化”大部分内容,这意味着将其提取到基类并使其可重用。现在,我有控制器、视图模型和EF6实体模型的基类 所有EF6实体继承的抽象基类: public abstract class BaseEntity<TSubclass> where TSubclass : BaseEntity<TSubclass> { publi

首先,规范。我们使用MVC5、.NET4.5.1和实体框架6.1

在我们的MVC5业务应用程序中,我们有很多重复的CRUD代码。我的工作是“自动化”大部分内容,这意味着将其提取到基类并使其可重用。现在,我有控制器、视图模型和EF6实体模型的基类

所有EF6实体继承的抽象基类:

public abstract class BaseEntity<TSubclass>
    where TSubclass : BaseEntity<TSubclass>
{
    public abstract Expression<Func<TSubclass, object>> UpdateCriterion();
}
之后,在我的基本控制器的
SaveOrUpdate
操作中,我会有如下代码:

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;
    }
}
public ActionResult Save(TViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        var entityModel = viewModel.ConstructEntityModel();
        db.Set<TEntityModel>().AddOrUpdate<TEntityModel>(entityModel.UpdateCriterion(), entityModel);
        db.SaveChanges();
    }
}
public abstract class BaseEntity<TSubclass> 
    where TSubclass : BaseEntity<TSubclass>
{
    public virtual Expression<Func<TSubclass, object>> UpdateCriterion()
    {
        return entity => ((dynamic)entity).ID;
    }
}
其目的是提供使用ID作为键的默认实现,并允许子类在使用不同键时重写ID。我不能使用带有ID字段的接口或基类,因为并非所有实体都有它。我想我应该使用
dynamic
来拉出
ID
字段,但我得到了以下错误:
错误:表达式树可能不包含动态操作


那么,你知道怎么做吗?反射是否在base
updateLiterion
中工作?

如果您定义的是BaseEntity类,则可以添加一个返回实际ID属性的虚拟只读属性。我相信EF将只读属性视为“计算的”,因此它们不会存储到数据库中

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

public partial class Foo : BaseEntity<Foo>
{
    public Int32 FooId { get; set; }
    public override object ID { get { return FooId; } } 
}
公共抽象类BaseEntity,其中TSubclass:BaseEntity
{
公共抽象对象ID{get;}
公共虚拟表达式UpdateLiterion()
{
返回entity=>entity.ID;
}
}
公共部分类Foo:BaseEntity
{
公共Int32 FooId{get;set;}
公共重写对象ID{get{return FooId;}}
}
只是一个想法-我只尝试在LinqPad中编译并检查对UpdateRiterion的调用的值。:)

看一看。它使用反射来获取ID属性。我认为它解决了你的问题:

public static object GetPropValue(object src, string propName)
{
    return src.GetType().GetProperty(propName).GetValue(src, null);
}
然后将lambda表达式替换为

return entity => GetPropValue(entity, "ID");

我还没有测试过,因为我没有完全测试它的代码。如果有效,请告诉我们。

否,您不能在Linq to实体查询中使用动态。 但是您可以在运行时构建Lambda表达式

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);
}
public虚拟表达式updateLiterion()
{
var param=Expression.Parameter(typeof(TSubclass));
var body=Expression.Convert(Expression.Property(param,“ID”),typeof(object));
返回表达式.Lambda(body,param);
}
如果TSubclass类型没有ID属性表达式。属性(param,“ID”)将引发异常


此外,您可以使用实体模型中的MetadataWorkspace来获取TSubclass的主键列

我很确定他不需要值,他需要表达式。没问题。Lambda Exp可以有方法调用(某些特定情况除外,例如编译为SQL的表达式)是的,但在这种情况下,结果用于DbSet的AddOrUpdate方法。这个方法需要PropertyExpression。谢谢,这正是我需要的!哦,另外,你知道如何在身体部位添加多个字段吗?像
e=>new{e.ID,e.Name}
?您知道如何用表达式类构建
e=>new{e.ID,e.Name}?
?在这种情况下,主体将是Expression.MemberInit。问题是匿名类型。如果使用p=>new{p.Prop1,p.Prop2}编写Lambda,编译器将创建具有匹配属性的具体类型。如果在运行时创建MemberInit,则匿名类型不存在,因此必须提供有效的现有类型
Expression.MemberInit(Expression.New(typeof(primarykeywithtwowalues)),Expression.Bind(…)或使用Reflection.Emit动态创建一个。谢谢,伙计,你太棒了。你有什么资源可以让我学到这样的东西吗?我找到的关于lambdas的所有东西都是匿名函数和一些LINQ。