C# 用于更新导航属性的通用数据访问层
我有以下通用数据访问类,负责数据库操作C# 用于更新导航属性的通用数据访问层,c#,.net,entity-framework,generics,C#,.net,Entity Framework,Generics,我有以下通用数据访问类,负责数据库操作 internal sealed class DataStore<T> : IDataStore<T> where T : BaseModel, new() { private readonly DataContext _context; public DataStore(DataContext context) { this._context = context; }
internal sealed class DataStore<T> : IDataStore<T>
where T : BaseModel, new()
{
private readonly DataContext _context;
public DataStore(DataContext context)
{
this._context = context;
}
public async Task InsertNew(T obj)
{
await Task.Run(async () =>
{
_context.Set<T>().Add(obj);
await _context.SaveChangesAsync();
});
}
public async Task<T> SelectObj(int id, Expression<Func<T, object>> includeExpression = null)
{
if (includeExpression != null)
return
await _context.Set<T>()
.Include<T, object>(includeExpression)
.FirstOrDefaultAsync(x => x.ID.Equals(id));
return await _context.Set<T>().Where(x => x.ID.Equals(id)).FirstOrDefaultAsync();
}
public async Task<List<T>> SelectAll(Expression<Func<T, object>> includeExpression = null)
{
if (includeExpression != null)
return await _context.Set<T>().Include<T, object>(includeExpression).ToListAsync();
return await _context.Set<T>().ToListAsync();
}
public async Task Update(T obj)
{
await Task.Run(async () =>
{
var original = await SelectObj(obj.ID);
_context.Entry(original).CurrentValues.SetValues(obj);
await _context.SaveChangesAsync();
});
}
public async Task Delete(T obj)
{
await Task.Run(async () =>
{
_context.Set<T>().Remove(obj);
await _context.SaveChangesAsync();
});
}
public async Task Delete(int id, Expression<Func<T, object>> includeExpression = null)
{
await Task.Run(async () =>
{
var obj = await SelectObj(id, includeExpression);
await Delete(obj);
});
}
}
经过反复研究,我最终得到了以下适用于我的应用程序的解决方案 下面是解决方案,并附有解释其作用的注释
private async Task UpdateNavProperties(T original, T newObject)
{
await Task.Run(async () =>
{
//get type of object
var objType = original.GetType();
//loop through properties on the Type
foreach (var prop in objType.GetProperties())
{
//Check that property is a class/reference type, and not part of the System namespace
//string would be part of the system namespace, but my custom class not
if (prop.PropertyType.IsClass && !prop.PropertyType.Namespace.Equals("System"))
{
//get the old value
var oldValue = prop.GetValue(original);
//get new value
var newValue = newObject.GetType().GetProperty(prop.Name).GetValue(newObject);
//update the value
_context.Entry(oldValue).CurrentValues.SetValues(newValue);
//save changes
await _context.SaveChangesAsync();
}
}
});
}
为了使用它,我做了以下工作:
public async Task Update(T obj, Expression<Func<T, object>> includeExpression = null)
{
await Task.Run(async () =>
{
var original = await SelectObj(obj.ID, includeExpression);
_context.Entry(original).CurrentValues.SetValues(obj);
await _context.SaveChangesAsync();
await UpdateNavProperties(original, obj);
});
}
公共异步任务更新(T obj,表达式includeExpression=null)
{
等待任务。运行(异步()=>
{
var original=等待选择对象(对象ID,包括表达式);
_context.Entry(原始).CurrentValues.SetValues(obj);
wait_context.SaveChangesAsync();
等待更新不动产(原件,obj);
});
}
玩了一番之后,我最终得到了适用于我的应用程序的以下解决方案
下面是解决方案,并附有解释其作用的注释
private async Task UpdateNavProperties(T original, T newObject)
{
await Task.Run(async () =>
{
//get type of object
var objType = original.GetType();
//loop through properties on the Type
foreach (var prop in objType.GetProperties())
{
//Check that property is a class/reference type, and not part of the System namespace
//string would be part of the system namespace, but my custom class not
if (prop.PropertyType.IsClass && !prop.PropertyType.Namespace.Equals("System"))
{
//get the old value
var oldValue = prop.GetValue(original);
//get new value
var newValue = newObject.GetType().GetProperty(prop.Name).GetValue(newObject);
//update the value
_context.Entry(oldValue).CurrentValues.SetValues(newValue);
//save changes
await _context.SaveChangesAsync();
}
}
});
}
为了使用它,我做了以下工作:
public async Task Update(T obj, Expression<Func<T, object>> includeExpression = null)
{
await Task.Run(async () =>
{
var original = await SelectObj(obj.ID, includeExpression);
_context.Entry(original).CurrentValues.SetValues(obj);
await _context.SaveChangesAsync();
await UpdateNavProperties(original, obj);
});
}
公共异步任务更新(T obj,表达式includeExpression=null)
{
等待任务。运行(异步()=>
{
var original=等待选择对象(对象ID,包括表达式);
_context.Entry(原始).CurrentValues.SetValues(obj);
wait_context.SaveChangesAsync();
等待更新不动产(原件,obj);
});
}
我知道我不是在回答你的问题,而是在工作中使用扳手。。。你会怎么做。。。如果只是“wait”context.savechangessync();`假设T obj最初是从上下文中提取的。我知道我不是在回答你的问题,而是在工作中使用扳手。。。你会怎么做。。。如果只是“wait”context.savechangessync();`假设T obj最初是从上下文中提取的。因为这是一个通用方法,所以即使没有缩进,它也将始终更新导航属性。1)如果需要只更新父级,则考虑该情况。此外,您还可以删除多个savechanges(),它将中断事务,如果发生错误,可能会影响在db中的部分保存。我将修改解决方案,以便其他用户阅读本文,但在我的示例中,我始终需要它来更新导航属性。我同意SaveChanges(),忘了这一点。感谢您的评论,因为这是一个通用方法,它将始终更新导航属性,即使没有缩进。1)如果需要只更新父级,则考虑该情况。此外,您还可以删除多个savechanges(),它将中断事务,如果发生错误,可能会影响在db中的部分保存。我将修改解决方案,以便其他用户阅读本文,但在我的示例中,我始终需要它来更新导航属性。我同意SaveChanges(),忘了这一点。谢谢你的评论