我有一个从POST请求获得的模型。由于我的视图定义了它的POCO类型,因此从提交的数据创建的对象也是POCO。作为POCO,它没有覆盖各种虚拟属性。因此,这些虚拟属性返回null。反过来,这意味着我必须根据外键进行单独的查询以浏览其属性(如果我想做更复杂的事情而不仅仅是保存它)。
考虑到我的模型的POCO,我可以获得具有所有被覆盖功能的代理吗?
(我假设这是db.Entry().Entity
的用途,但它仍然返回POCO对象,而不是代理。我在断点暂停期间通过鼠标悬停检查对象的运行时类型。 )
答案 0 :(得分:7)
此代码的某些内容将满足您的需求。我使用automapper将值从传入的实体复制到代理版本。
代码检查传入的实体是否是代理,并相应地处理它。
public class Repository<T> where T : class
{
private readonly Context context;
private bool mapCreated = false;
public Repository(Context context)
{
this.context = context;
}
protected virtual T InsertOrUpdate(T e, int id)
{
T instance = context.Set<T>().Create();
if (e.GetType().Equals(instance.GetType()))
instance = e;
else
{
if (!mapCreated)
{
Mapper.CreateMap(e.GetType(), instance.GetType());
mapCreated = true;
}
instance = Mapper.Map(e, instance);
}
if (id == default(int))
context.Set<T>().Add(instance);
else
context.Entry<T>(instance).State = EntityState.Modified;
return instance;
}
}
更新版本
public class Repository<T> where T : class
{
private readonly Context context;
public Repository(Context context)
{
this.context = context;
}
protected virtual T InsertOrUpdate(T e, int id)
{
T instance = context.Set<T>().Create();
if (e.GetType().Equals(instance.GetType()))
{
instance = e;
}
else
{
DbEntityEntry<T> entry = context.Entry(instance);
entry.CurrentValues.SetValues(e);
}
context.Entry<T>(instance).State =
id == default(int)
? EntityState.Added
: EntityState.Modified;
return instance;
}
}
答案 1 :(得分:1)
db.Entry()。实体将始终返回POCO,并且不会返回处理虚拟导航属性实现的代理对象:
var o = db.Entry(myPoco).Entity; // always returns a POCO
在针对数据库上下文调用Find()
或Where()
时,通常会获得代理对象而不是POCO。 但是,在首次将对象添加到数据库的上下文中,这些方法将(意外地?)返回POCO而不是代理对象。实际上你必须离开上下文并打开一个新的来获取代理:
// create a new POCO object, and connect to it to another object already in the DB
MyPoco myPoco = new MyPoco();
myPoco.MyOtherPocoId = myPoco2.MyOtherPocoId; // make reference to existing object
using (var db = new MyContext())
{
// Add myPoco to database.
db.MyPocos.Add(myPoco);
db.SaveChanges();
// One would think you get a proxy object here, but you don't: just a POCO
var test10 = db.MyPocos.Find(myPoco.Id); // returns a MyPoco
var test11 = db.MyPocos.Where(x => x.Id == myPoco.Id).First(); // returns a MyPoco
var test12 = db.Entry(myPoco).Entity; // returns a MyPoco
// ...so, you can't access the referenced properties through virtual navigation properties:
MyOtherPoco otherPoco1 = myPoco.Poco2; // returns NULL
}
// leave the context and build a new one
using (var db = new MyContext())
{
// Now, the same Find() and Where() methods return a proxy object
var test20 = db.MyPocos.Find(myPoco.Id); // returns a proxy object
var test21 = db.MyPocos.Where(x => x.Id == myPoco.Id).First(); // returns a proxy object
// ...which means the virtual properties can be accessed as expected:
MyOtherPoco otherPoco = myPoco.Poco2; // works as expected
// Note that db.Entry().Entity still returns a POCO:
var test22 = db.Entry(myPoco).Entity; // returns a MyPoco
}
可能会有一些神奇的咒语使得添加对象的上下文会给你一个代理对象,但我还没有遇到它。
答案 2 :(得分:0)
如果您想通过MVC控制器执行此操作,可以使用类似的操作:
[HttpPost]
public ActionResult Update(int? id, FormCollection form)
{
// assumes repository will handle
// retrieving the entity and
// including and navigational properties
var entity = repository.Get(id);
if (entity == null)
{
throw new InvalidOperationException(string.Format("Not found: {0}", id));
}
if (TryUpdateModel(entity))
{
try
{
//
// do other stuff, add'l validation, etc
repository.Update(entity);
}
catch (Exception ex)
{
//
// exception cleansing/handling
// add'l model errors
return View(entity);
}
return View("Success", entity);
}
return View(entity);
}