我的SurveyController类中有这个方法:
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运算符创建了实体,因此从未创建支持延迟加载的代理,当我访问它时它为null。当我们直接访问DbContext时,我们可以使用Create方法explicitly create the proxy。但是我在这里有一个工作单元和存储库模式。我想我可以通过repository.Create方法公开context.Create方法然后我需要记住在添加实体时使用它而不是new运算符。但是在我的InsertOrUpdate方法中封装问题不是更好吗?是否有某种方法可以检测到添加的实体是否应该是代理并替换代理?这是我的基础存储库类中的InsertOrUpdate方法:
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;
}
}
答案 0 :(得分:3)
根据qujck提供的答案。以下是您无需使用automapper即可完成的任务:
已编辑以始终检查代理 - 不仅仅是在插入期间 - 正如评论中所建议的那样
再次编辑以使用不同的方式检查代理是否已传入方法。改变技术的原因是当我引入从另一个继承的实体时遇到了问题。在这种情况下,即使是代理,继承的实体也可能无法通过entity.e.GetType().Equals(instance.GetType()
检查。我从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; }
}
答案 1 :(得分:1)
我同意你的意见,这应该在一个地方处理,并且最好的地方可以捕捉所有看起来是你的存储库。您可以将T
的类型与上下文创建的实例进行比较,并使用Automapper之类的内容快速传输所有值,如果类型不匹配的话。
private bool mapCreated = false;
protected virtual void InsertOrUpdate(T e, int id)
{
T instance = context.Set<T>().Create();
if (e.GetType().Equals(instance.GetType()))
instance = e;
else
{
//this bit should really be managed somewhere 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(instance).State = EntityState.Modified;
}