在实体框架中使用存储库模式时,如何确保创建代理? [英] How to ensure proxies are created when using the repository pattern with entity framework?
问题描述
我的 SurveyController 类中有这个方法:
I have this method in my SurveyController class:
public ActionResult AddProperties(int id, int[] propertyids, int page = 1)
{
var survey = _uow.SurveyRepository.Find(id);
if (propertyids == null)
return GetPropertiesTable(survey, page);
var repo = _uow.PropertySurveyRepository;
propertyids.Select(propertyid => new PropertySurvey
{
//Setting the Property rather than the PropertyID
//prevents the error occurring later
//Property = _uow.PropertyRepository.Find(propertyid),
PropertyID = propertyid,
SurveyID = id
})
.ForEach(x => repo.InsertOrUpdate(x));
_uow.Save();
return GetPropertiesTable(survey, page);
}
GetPropertiesTable 重新显示属性,但 PropertySurvey.Property 被标记为虚拟,并且我使用 new 运算符创建了实体,因此从未创建支持延迟加载的代理,当我访问它时它为空.当我们可以直接访问 DbContext 时,我们可以使用 Create 方法显式创建代理一>.但是我在这里有一个工作单元和存储库模式.我想我可以通过 repository.Create 方法公开 context.Create 方法,然后我需要记住在添加 entity 时使用它而不是 new 运算符.但是将问题封装在我的 InsertOrUpdate 方法中不是更好吗?是否有某种方法可以检测添加的实体在应该是代理时不是代理并替换代理?这是我的基本存储库类中的 InsertOrUpdate 方法:
The GetPropertiesTable redisplays Properties but PropertySurvey.Property is marked virtual and I have created the entity using the new operator, so a proxy to support lazy loading was never created and it is null when I access it. When we have access direct to the DbContext we can use the Create method to explicitly create the proxy. But I have a unit of work and repository pattern here. I guess I could expose the context.Create method via a repository.Create method and then I need to remember to use that instead of the new operator when I add an entity . But wouldn't it be better to encapsulate the problem in my InsertOrUpdate method? Is there some way to detect that the entity being added is not a proxy when it should be and substitute a proxy? This is my InsertOrUpdate method in my base repository class:
protected virtual void InsertOrUpdate(T e, int id)
{
if (id == default(int))
{
// New entity
context.Set<T>().Add(e);
}
else
{
// Existing entity
context.Entry(e).State = EntityState.Modified;
}
}
推荐答案
基于 qujck 提供的答案.以下是无需使用自动映射器即可完成此操作的方法:
Based on the answer supplied by qujck. Here is how you can do it without having to employ automapper:
编辑始终检查代理 - 不仅仅是在插入期间 - 正如评论中所建议的
Edited to always check for proxy - not just during insert - as suggested in comments
再次编辑以使用不同的方式来检查是否已将代理传递给方法.更改技术的原因是我在引入从另一个继承而来的实体时遇到了问题.在这种情况下,即使是代理,继承的实体也可能无法通过 entity.e.GetType().Equals(instance.GetType()
检查.我从 这个答案
Edited again to use a different way of checking whether a proxy was passed in to the method. The reason for changing the technique is that I ran into a problem when I introduced an entity that inherited from another. In that case an inherited entity can fail the entity.e.GetType().Equals(instance.GetType()
check even if it is a proxy. I got the new technique from this answer
public virtual T InsertOrUpdate(T e)
{
DbSet<T> dbSet = Context.Set<T>();
DbEntityEntry<T> entry;
if (e.GetType().BaseType != null
&& e.GetType().Namespace == "System.Data.Entity.DynamicProxies")
{
//The entity being added is already a proxy type that supports lazy
//loading - just get the context entry
entry = Context.Entry(e);
}
else
{
//The entity being added has been created using the "new" operator.
//Generate a proxy type to support lazy loading and attach it
T instance = dbSet.Create();
instance.ID = e.ID;
entry = Context.Entry(instance);
dbSet.Attach(instance);
//and set it's values to those of the entity
entry.CurrentValues.SetValues(e);
e = instance;
}
entry.State = e.ID == default(int) ?
EntityState.Added :
EntityState.Modified;
return e;
}
public abstract class ModelBase
{
public int ID { get; set; }
}
这篇关于在实体框架中使用存储库模式时,如何确保创建代理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!