创建通用存储库InsertOrUpdate函数(错误)

时间:2014-05-03 19:55:36

标签: c# entity-framework generics

我试图在我的通用存储库上的抽象层上创建一个InsertOrUpdate函数,由我的具体对象存储库继承:

这是我的代码:

 public abstract class GenericRepository<T> : IGenericRepository<T> where T : class
 {
    private readonly OhmioEntities context = new OhmioEntities();

    public IQueryable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
    {
        IQueryable<T> query = context.CreateObjectSet<T>().Where(predicate);
        return query;
    }

    public void InsertOrUpdate(T entity, System.Linq.Expressions.Expression<Func<T, bool>> Findpredicate)
    {   
        T _dbRecord = this.FindBy(Findpredicate).FirstOrDefault();
        if (_dbRecord != null)
        {
            // Edit the record
            _dbRecord = entity;
            context.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified);
        }
        else
        {
            // Agrego el registro
            context.CreateObjectSet<T>().AddObject(entity);
        }

        // Save Changes to DB
        context.SaveChanges();
    }
} 

我这样用:

public class ClientsRepository : GenericRepository<Clients>
{
  Clients _cli = new Clients(){ClientID=1,ClienName="My New Client"};
  this.InsertOrUpdate(_cli, o => o.ClientID == 1);
}

这个想法是,如果ClientID = 1 Existe,记录将被编辑。如果没有插入新记录。它在插入新对象时非常有效,但它在这一行上给出了错误:

context.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified);

那说:

  

{&#34; ObjectStateManager不包含ObjectStateEntry,引用类型&#39; DataLayer.Clients&#39;。&#34;}

的对象

为什么我会这样?任何线索?谢谢!

UDATE

嗯,我开始工作它只需要更多的代码:

public void InsertOrUpdate(T entity, System.Linq.Expressions.Expression<Func<T, bool>> Findpredicate)
    {   
        T _dbRecord = this.FindBy(Findpredicate).FirstOrDefault();
        if (_dbRecord != null)
        {
            // Edit the object
            context.ObjectStateManager.ChangeObjectState(_dbRecord, System.Data.EntityState.Modified);
            context.Detach(_dbRecord);
            _dbRecord = entity;
            context.AttachTo(entity.ToString().Split('.')[2], _dbRecord);
            context.ObjectStateManager.ChangeObjectState(_dbRecord, System.Data.EntityState.Modified);                                
        }
        else
        {
            // add the object
            context.CreateObjectSet<T>().AddObject(entity);
        }

        // Save Changes to DB
        context.SaveChanges();
    }

2 个答案:

答案 0 :(得分:1)

您已经创建了一个新的Client对象,但我想还没有在上下文中添加。首先尝试在上下文中添加,然后将其状态更改为Modified

另外,您的FindBy函数正在被用作信号,也许您可​​以使用Any函数而不是在此函数中实际加载实体并将返回类型更改为boolean

您的类的示例用法还有一点奇怪。我不确定我们是否可以直接调用类中的方法,而不是在其他方法中使用此方法。

答案 1 :(得分:1)

您的UPDATE中的加载和分离技巧不是必需的。您只能在不加载实体的情况下询问数据库是否已存在(使用Any()而不是FirstOrDefault()):

public void InsertOrUpdate(T entity, Expression<Func<T, bool>> Findpredicate)
{   
    bool exists = this.FindBy(Findpredicate).Any();
    if (exists)
    {
        context.CreateObjectSet<T>().Attach(entity);
        context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
    }
    else
    {
        context.CreateObjectSet<T>().AddObject(entity);
    }

    context.SaveChanges();
}

或者,您可以从数据库加载原始实体,并使用修改后的分离实体(使用ApplyCurrentValues)更新其属性。它的好处是,只有真正更改的属性与UPDATE语句一起发送到数据库(但代价是必须加载原始实体),同时将整个实体状态设置为Modified也将发送更新到DB的未更改的属性(但有一个好处是原始的不需要加载):

public void InsertOrUpdate(T entity, Expression<Func<T, bool>> Findpredicate)
{   
    T _dbRecord = this.FindBy(Findpredicate).FirstOrDefault();
    if (_dbRecord != null)
    {
        context.CreateObjectSet<T>().ApplyCurrentValues(entity);
    }
    else
    {
        context.CreateObjectSet<T>().AddObject(entity);
    }

    context.SaveChanges();
}

请注意,这两种解决方案仅用于更新实体的标量属性。它不适用于已更改的关系和导航属性。对于具有任意对象图的更一般的更新方案,没有简单的泛型解决方案。