【问题标题】:Possible to dynamically join a related model in Entity Framework Core?可以在 Entity Framework Core 中动态加入相关模型吗?
【发布时间】:2021-07-09 23:20:17
【问题描述】:

假设有一个项目涉及很多表,所有表都引用一个包含名为group ID 的字段的表。但是,并非所有表都直接引用该单个表。

例如,数据库包含一个garages 表,每个车库由cars 表中的行引用,每辆汽车由tire 表中的行引用。我想将数据组织成两组,group1group2。每个车库都有一个group ID,但是汽车和轮胎没有。这是表格的示意图:

如您所见,第 1 组中的资产以红色突出显示,第 2 组中的资产以黄色突出显示。但并非所有突出显示的行都必须具有组 ID。您可以想象这可能会持续更长的时间,轮毂盖各自的轮胎具有伪造的钥匙,各自的轮毂盖上带有伪造的钥匙的螺栓等等。

如果给定子车、轮胎、轮毂盖等,有没有办法动态调用可以从相关车库获取group ID 的 EF 查询?实现可能是这样的:

var tire = Context.Tires.where(t => t.ID == 3).FirstOrDefault<Tire>();
tire.findShortestJoinToEntity(entity => entity.GetProperty("GroupID") != null);
// Returns 2, the group of "Toyota Tires"

在更专业的术语中,它需要递归检查传入模型中的任何伪造密钥,然后是引用模型的所有伪造密钥,所有它们引用的模型等,直到没有更多伪造密钥或找到具有传入名称的字段。

【问题讨论】:

  • 您能告诉我们这些类包含哪些属性,以及它们之间的关系吗?或者,您可以尝试绘制一个简单的数据库图,这样可以帮助我们更清楚地了解您的需求。
  • 为什么这需要是动态的? Linq 表达式已经为我们做到了这一点,但是以一种类型安全的方式,您需要将字段名称转换为字符串的用例是什么?
  • 您是否正在专门寻找基于 SQL 的解决方案?
  • 它需要是动态的,因为它检查了未指定数量的实体。我不一定需要传入一个字符串,只需传递一些东西来识别我正在寻找的字段。我实际工作的项目需要 SQL,并且有多个具有此 GroupID 的表。目标是使用 GroupID(也就是最少的连接数)找到对最近表的查询,然后通过路径追踪到那里,为我正在调用的特定项目找到正确的 GroupID。跨度>
  • 这可能是 sql 规范化走得太远的情况。此数据是只读的还是您需要对其进行更新?您是否能够创建一个定时流程来将这些数据提取到一个平面表中以供该项目使用?如果你不能这样做,那么考虑一个 sql 视图。与编写 ef 体操相比,从单个表中提取对系统造成的压力要小得多。

标签: sql asp.net-core entity-framework-core


【解决方案1】:

我认为您可以使用反射来做到这一点,由于可能存在性能问题,它不是理想的解决方案,但它可以满足您的需求。

这里的关键思想是让所有实体类实现一个公共接口IEntity,这样我们就可以在任何实体上调用递归方法。还假设我们在任何实体中都有 parentId(外键)和父对象,尽管您可以调整该方法以仅使用 parentId,但我将父对象仅用于利用链接父实体和子实体的 EF 跟踪机制

    public interface IEntity
    {
        int Id { get; set; }
    }

    public class Group : IEntity
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Garage : IEntity
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual int GroupId { get; set; }
        public virtual Group Group { get; set; }
    }

    public class Car : IEntity
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual int GarageId { get; set; }
        public virtual Garage Garage { get; set; }
    }

    // ... other entity classes here


    public static class EntityExtensions
    {
        public static int FindGroupId(this IEntity entity, Context context, string propertyName = null)
        {
            var groupId = 0;

            if (entity != null)
            {
                var entityType = entity.GetType();

                if (entity is Group)
                {
                    // we found it
                    groupId = propertyName == null
                        ? entity.Id
                        : (int)entityType.GetProperty(propertyName).GetValue(entity);
                }
                else
                {
                    // look into properties for parent entities
                    foreach (var property in entityType.GetProperties())
                    {
                        if (property.GetGetMethod().IsVirtual
                            && property.PropertyType.GetInterface(nameof(IEntity)) != null)
                        {
                            // it is parent entity
                            var parentEntity = property.GetValue(entity) as IEntity;

                            if (parentEntity == null)
                            {
                                // if parent entity is null, let's get it from db
                                var parentIdName = $"{property.PropertyType.Name}Id";
                                var parentId = (int)entityType.GetProperty(parentIdName).GetValue(entity);
                                parentEntity = context.Find(property.PropertyType, parentId) as IEntity;
                            }

                            groupId = FindGroupId(parentEntity, context, propertyName);
                        }

                        if (groupId > 0)
                        {
                            // we found it
                            break;
                        }
                    }
                }
            }

            return groupId;
        }
    }

【讨论】:

    猜你喜欢
    • 2020-08-31
    • 2019-12-06
    • 2020-06-16
    • 1970-01-01
    • 2019-03-09
    • 2022-08-20
    • 1970-01-01
    • 2019-01-11
    • 1970-01-01
    相关资源
    最近更新 更多