我试图在我的通用存储库上的抽象层上创建一个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();
}
答案 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();
}
请注意,这两种解决方案仅用于更新实体的标量属性。它不适用于已更改的关系和导航属性。对于具有任意对象图的更一般的更新方案,没有简单的泛型解决方案。