当使用实体框架的存储库模式时,如何确保代理被创建? [英] How to ensure proxies are created when using the repository pattern with entity framework?

查看:94
本文介绍了当使用实体框架的存储库模式时,如何确保代理被创建?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在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
{
//设置属性而不是PropertyID
//防止以后发生的错误
// Property = _uow.PropertyRepository.Find(propertyid),
PropertyID = propertyid,
SurveyID = id
})
.ForEach(x => repo.InsertOrUpdate X));
_uow.Save();

return GetPropertiesTable(survey,page);
}

GetPropertiesTable重新显示属性,但PropertySurvey.Property标记为虚拟,并且我创建了实体使用新的运算符,所以一个代理来支持延迟加载从未被创建,当它访问它是空的。当我们直接访问DbContext时,我们可以使用Create方法明确创建代理。但我在这里有一个工作单位和仓库模式。我想我可以通过repository.Create方法暴露context.Create方法,然后在添加实体时,我需要记住使用而不是新的运算符。但是在InsertOrUpdate方法中封装问题不是更好吗?有没有办法检测到被添加的实体不是代理,而是代理代理?这是我的基本存储库类中的InsertOrUpdate方法:

  protected virtual void InsertOrUpdate(T e,int id)
{
if(id == default(int))
{
//新实体
context.Set< T>()
}
else
{
//现有实体
context.Entry(e).State = EntityState.Modified;
}
}


在qujck提供的答案。以下是您可以如何使用自动取款程序:



已编辑始终检查代理 - 不只是在插入期间 - 如评论



再次编辑使用不同的方法来检查代理是否传递给该方法。改变技术的原因是当我引入一个继承自另一个的实体时遇到了一个问题。在这种情况下,继承的实体可能会失败 entity.e.GetType()。Equals(instance.GetType()检查即使它是一个代理,我得到了新的技术来自此答案

  public virtual T InsertOrUpdate(T e)
{
DbSet< T> dbSet = Context.Set< T>();

DbEntityEntry< T>条目;
if(e.GetType()。BaseType!= null
&& e.GetType()。Namespace ==System.Data.Entity.DynamicProxies)
{
/ /被添加的实体已经是支持lazy
//加载的代理类型 - 只需获取上下文条目
entry = Context.Entry(e);
}
else
{
//已添加的实体已使用new运算符创建
//生成代理类型以支持延迟加载并附加
T instance = dbSet。 Create();
instance.ID = e.ID;
en try = Context.Entry(instance);
dbSet.Attach(instance);

//并将其设置为实体的值
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;组; }
}


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);
}

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;
        }
    }

解决方案

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆