繁体   English   中英

实体框架 - 按名称获取实体

[英]Entity framework - get entity by name

我有以下代码(示例):

public dynamic GetData(string name) 
{
    using(var ctx = GetObjectContext()) 
    {
        switch (name) 
        {
        case "entity1":
            return ctx.entity1.ToList();
        case "entity2":
            return ctx.entity2.ToList();
        ......
        default:
            return null;
        }
    }
}

我想避免在这个示例中切换。 如何按名称找到所需的实体 class,调用 ToList() 方法并返回数据? 我可以使用反射来做到这一点吗?

您可以使用反射来实现,但是您还需要使用泛型,因为 ToList() 方法返回的列表类型对于每个实体类型都是不同的。

您可以通过反射访问属性 getter,如下所示:

var enumerable = typeof([ClassNameOfContext]).GetProperty(name).GetValue(ctx, null);

[ClassNameOfContext]是 ctx 是其实例的类的名称。 这从您的代码中并不明显,但您知道:-)

问题是enumerable将是一个object ,必须转换为IEnumerable<EntityType> ,其中EntityType是您正在访问的实体类型。 换句话说,这取决于您传递的名称。 如果您使用泛型来确定类型,您将能够正确地转换对象,甚至不必返回dynamic

public TEntity Get<TEntity>(string name)
{
    ...

并从上面转换线:

var enumerable = (IEnumerable<TEntity>)(typeof([ClassNameOfContext]).GetProperty(name).GetValue(ctx, null));
return enumerable.ToList();

干得好!

附录:可以想象,您也可以摆脱字符串参数 - 应尽可能避免在字符串中使用类型或属性的名称,因为它不是类型安全的。 编译器无法识别它,并且 IDE 功能(例如重构)没有考虑到它。 这里的问题是属性名称通常是实体类型名称的复数形式。 但是您可以使用反射来查找类型与TEntity匹配的属性。 我把它留作练习:-)

你可以使用这样的代码

private IEnumerable<TEntity> GetList<TEntity>(string connectionString, Func<object, T> caster)
{
    using (var ctx = new DbContext(connectionString))
    {
        var setMethod = ctx.GetType().GetMethod("Set").MakeGenericMethod(typeof(T));

        var querable = ((DbSet<object>)setMethod
        .Invoke(this, null))
        .AsNoTracking()
        .AsQueryable();

        return querable
            .Select(x => caster(x))
            .ToList();
    }
}

像这样调用:

var branchList = GetList<Branch>("connectionStringName", x => (Branch)x);

您可以删除 .AsNoTracking() 并删除 .ToList(),然后您将获得可以进一步查询的纯 IQueryable。

在@chiccodoro 的出色回答的帮助下,我创建了一种包含所有相关实体的方法。 使用具有 7 个导航属性的实体“产品”

public static IQueryable<T> IncludeAllEntities<T>(this DbSet<T> entity, DataContext context) where T : class
        {
            var querable = entity.AsQueryable();

            var type = typeof(T);
            var entityType= context.Model.FindEntityType(type);
            var navs = entityType?.GetNavigations();
            if (navs==null)
            {
                return null;
            }
            List<string> navNames = new List<string>();
            foreach (var nav in navs)
            {
                navNames.Add(nav.Name);
            }
            try
            {
                var agg = navNames.Aggregate(querable, (acc, name) => acc.Include(name));
                return agg;
            }
            catch (Exception ex)
            {

                throw;
            }
        }

在这里,我获取实体的类型以获取导航属性,然后将每个实体的名称添加到字符串列表中,然后聚合列表以包含每个实体。
那么我们可以像这样使用这个扩展方法:

var record= await _context.Products.IncludeAllEntities(_context).FirstOrDefaultAsync(x => x.Id == key);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM