【发布时间】:2014-08-25 20:44:18
【问题描述】:
首先,规格。我们使用 MVC5、.NET 4.5.1 和实体框架 6.1。
在我们的 MVC5 业务应用程序中,我们有很多重复的 CRUD 代码。我的工作是“自动化”大部分内容,这意味着将其提取到基类并使其可重用。现在,我有控制器、视图模型和 EF6 实体模型的基类。
我的所有 EF6 实体都继承的抽象基类:
public abstract class BaseEntity<TSubclass>
where TSubclass : BaseEntity<TSubclass>
{
public abstract Expression<Func<TSubclass, object>> UpdateCriterion();
}
UpdateCriterion 方法用于数据库上下文的AddOrUpdate 方法。我有一个子类的通用参数,因为UpdateCriterion 需要返回使用精确子类类型的 lambda 表达式,而不是接口或基类。实现此抽象基类的极其简化的子类如下所示:
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 操作中,我将有这样的代码:
public ActionResult Save(TViewModel viewModel)
{
if (ModelState.IsValid)
{
var entityModel = viewModel.ConstructEntityModel();
db.Set<TEntityModel>().AddOrUpdate<TEntityModel>(entityModel.UpdateCriterion(), entityModel);
db.SaveChanges();
}
}
多亏了这一点,基本控制器的子类不需要像以前那样自己实现Save 方法。现在,所有这些都有效,尽管语法很时髦(我的意思是,class BaseEntity<TSubclass> where TSubclass : BaseEntity<TSubclass>,认真的?),它实际上工作得很好。
我的问题来了。对于大多数实体字段ID 是关键,但对于某些不是,所以我不能用超类实现正确概括。所以现在,每个实体子类都实现了它自己的UpdateCriterion。但是,因为对于大多数(90%+)实体e => e.ID 是正确的实现,我有很多重复。所以我想把实体基类改写成这样:
public abstract class BaseEntity<TSubclass>
where TSubclass : BaseEntity<TSubclass>
{
public virtual Expression<Func<TSubclass, object>> UpdateCriterion()
{
return entity => ((dynamic)entity).ID;
}
}
目的是提供使用 ID 作为键的默认实现,并允许子类在使用不同的键时覆盖它。我不能使用带有 ID 字段的接口或基类,因为并非所有实体都有它。我以为我会使用dynamic 拉出ID 字段,但出现以下错误:Error: An expression tree may not contain a dynamic operation。
那么,你知道如何做到这一点吗?反射会在UpdateCriterion 基础上工作吗?
【问题讨论】:
标签: c# .net linq entity-framework lambda