我有以下类(修剪为仅显示基本结构):
public abstract class BaseModel {
public bool PersistChanges() {
// Context is of type "ObjectContext"
DatabaseHelper.Context.SafelyPersistChanges(this);
}
}
public static class ObjectContextExtensions {
public static bool SafelyPersistChanges<T>(this ObjectContext oc, T obj) {
// Persist the object using a transaction
}
}
[Persistent("LEADS")]
public class Lead : BaseModel {
// Extra properties
}
public class LeadsController : Controller {
public ActionResult Save(Lead lead) {
lead.PersistChanges()
}
}
我的潜在客户类派生自 BaseModel ,其中包含使用事务将对象的更改持久保存到数据库的方法。我用扩展方法实现了事务持久化。问题是,通过在 BaseModel 类中将此传递给 SafelyPersistChanges ,扩展方法上的泛型T设置为 BaseModel < / strong>即可。但是,由于 BaseModel 未标记为持久对象(它不能),因此ORM框架会抛出异常。
示例:
Lead lead = LeadRepository.FindByNumber(2);
lead.SalesmanNumber = 4;
// Calls "ObjectContextExtensions.SafelyPersistChanges<BaseModel>(BaseModel obj)"
// instead of "ObjectContextExtensions.SafelyPersistChanges<Lead>(Lead obj)"
lead.PersistChanges();
上述块引发了以下异常:
如果没有持久属性,则无法为“SalesWeb.Data.BaseModel”类型创建映射。
有什么想法吗?
答案 0 :(得分:3)
扩展方法在编译时是静态绑定的。在调用SafelyPersistChanges时,它被输入为BaseModel,因此也是您的异常。为了获得你想要的行为,你需要做一个带有大量转换的丑陋if语句或者强制调用派生类。
使PersistChanges成为一种抽象方法。然后使用完全相同的代码在派生类中实现调用。
public class Lead {
public override bool PersistChanges() {
// Context is of type "ObjectContext"
DatabaseHelper.Context.SafelyPersistChanges(this);
}
}
现在这将成为Lead
答案 1 :(得分:1)
我会以不同的方式设计它,使“public bool PersistChanges()”调用一个虚方法,在每个子类中重写。
答案 2 :(得分:0)
因此,您需要一个“单一”实现,它根据调用者已知的类型而变化。听起来像是Generics的工作。
public static bool PersistChanges<T>(this T source)
where T : BaseModel
{
// Context is of type "ObjectContext"
//static property which holds a Context instance is dangerous.
DatabaseHelper.Context.SafelyPersistChanges<T>(source);
}
答案 3 :(得分:0)
您可以使用curiously recurring template pattern:
解决此问题// change your code to this
public abstract class BaseModel<TDerived> where TDerived : BaseModel
{
public bool PersistChanges() {
// Context is of type "ObjectContext"
DatabaseHelper.Context.SafelyPersistChanges((TDerived)this);
// ^
// note the cast here: -----------------------|
}
}
public class Lead : BaseModel<Lead> { }
// the rest of your code is unchanged
这样可行,但我可能只是遵循其他建议并使用虚拟方法。