理想情况下,我希望:
public user Update(User dto) {
var user = userRepository.GetUserById(dto.Id);
var mergedFields = Merge(user, dto); //my dream function
userRepository.UpdateOnly(user, mergedFields)
.Where(u => u.Id == user.Id); //OrmLite UpdateOnly func
return user;
}
Merge
是我的deam函数返回Linq表达式:
Expression<Func<T, TKey>> Merge(T target, T source)
因此,Merge
知道从T源更新到T目标的内容。更新target中这些属性的值,并将这些更新的属性作为Linq Expression for OrmLite UpdateOnly返回使用。
然而,我正在拉我的头发,我无法弄清楚如何编写这个Merge
函数。请给我一些帮助!
谢谢!
参考:ServiceStack OrmLite是light weight ORM。它的UpdateOnly
函数采用这样的Linq表达式:
.UpdateOnly(new User {FirstName="admin", LastName="my", OtherStuff="etc..."},
u => {u.FirstName, u.LastName}).Where(u => u.Id == 123);
答案 0 :(得分:3)
虽然我可以看到你想要做什么,但已经有一个内置机制来实现部分更新,而不必构建更改值的Linq表达式。
我认为OrmLite的UpdateNonDefaults
更适合您的任务。
您的更新操作应该只接收对DTO中现有记录的更改,而不是完整对象。所以这样做应该足够了:
db.UpdateNonDefaults(dto, u => u.Id == 123);
SQL中的结果:
UPDATE "User" SET "FirstName" = 'admin', "LastName" = 'my' WHERE ("UserId" = 123);
如果您的更新请求其中包含完整对象,则数据库只会覆盖具有相同值的所有现有值,但此操作的成本不应超过查找时间的处理时间。整个现有对象,进行比较以使用反射确定更改,构建Linq表达式并运行UpdateOnly
查询。
如果您已经设置了检查更改字段与原始字段,那么您可以在没有Linq表达式的复杂性的情况下执行此操作。您的合并功能可以执行此操作(PseudoCode):
public T Merge(T target, T source)
{
var result = default(T);
反映您的T target
公共媒体资源:
foreach(var property in target.GetType().GetPublicProperties()){
每个反射属性:
使用EqualityComparer
确定值是否已更改:
if(!EqualityComparer<FieldType>.Default.Equals(targetField, sourceField))
如果值不同,请在result
对象上设置值。
返回result
个对象。它只会有变化。
现在使用UpdateNonDefaults
结果将确保只有更改包含在更新SQL中。
检查更改的字段是否值得?您应该运行一些基准测试。请记住,检查涉及:
如果您在确定对象的更改时遇到困难,the answers in this question可能会有所帮助。
我希望这会有所帮助。