【问题标题】:Generic Data Access layer to update navigational properties用于更新导航属性的通用数据访问层
【发布时间】:2017-05-25 07:46:44
【问题描述】:

我有以下通用数据访问类,负责数据库操作。

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

Update 函数的问题在于,它只更新通过的T 对象,而不是该对象的导航属性。

我已经尝试了以下操作,但我被卡住了,不知道我需要如何继续。

private void GetNavProperties(T obj)
    {
        var objType = obj.GetType();
        foreach (var prop in objType.GetProperties())
        {
            if (prop.PropertyType.IsClass)
            {
                var values = prop.GetValue(obj);
                //How do I go further here, setting the Entity on the context
            }
        }
    }

【问题讨论】:

  • 我知道我不是在回答你的问题,而是在工作中扔一个扳手......更新会做什么......如果它只是'await _context.SaveChangesAsync();'提供T obj 最初是从上下文中提取的。

标签: c# .net entity-framework generics


【解决方案1】:

在玩了之后,我最终得到了以下适用于我的应用程序的解决方案。

下面是解决方案,用 cmets 来解释它的作用。

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

【讨论】:

  • 由于这是一个通用方法,即使没有缩进,它也会始终更新导航属性。 1)如果您只需要更新Parent,请考虑这种情况。此外,您还可以删除多个 savechanges() 它会破坏事务,如果发生错误,可能会影响数据库中的部分保存。
  • 为了让其他用户阅读这篇文章,我将修改解决方案,但对于我的示例,我总是需要它来更新导航属性。我同意 SaveChanges(),忘记了。谢谢你的cmets
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多