创建通用存储库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();
}
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
。
还有一件事,你的类的示例用法有点奇怪。