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

本文关键字:函数 错误 InsertOrUpdate 存储 创建 | 更新日期: 2023-09-27 18:01:44

我试图在通用存储库的抽象层上创建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);

说:

{"ObjectStateManager不包含引用类型为' datallayer . clients '的对象的ObjectStateEntry。"}

为什么我得到这个?有线索吗?谢谢!

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

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

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也会将未改变的属性随着UPDATE发送到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();
}

注意,这两种解决方案只适用于更新实体的标量属性。它不适用于改变了的关系和导航属性。对于这种具有任意对象图的更通用的Update场景,没有简单的通用的解决方案。

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

加上你的FindBy函数被用作一个信号,也许你可以使用Any函数而不是实际加载这个函数中的实体,并将返回类型更改为boolean

还有一件事,你的类的示例用法有点奇怪。

我不确定我们是否可以直接在一个类中调用一个方法,而不需要在其他方法中使用这个方法。