使用 Linq/Lambda 表达式将对象组合成新模型

Combining Objects into a new model with Linq/Lambda expressions

我正在开发一个 Blazor 项目并使用 Dapper 从 SQL 数据库中提取数据。 我现在正在拉 3 tables。实体 table、专业 table 和桥梁 table 用于维护实体和专业之间的多对多关系。

我可以很好地从 SQL 中提取数据,我想合并我的数据服务中的数据并将其作为新的对象模型注入到 Blazor 组件中。

以下是模型:

实体

public class EntityModel : IEntityModel
    {
        public int Id { get; set; }
        public int PhysicianId { get; set; }
        public int PartnerId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

专业

 public class SpecialtyModel : ISpecialtyModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

桥模型

public class BridgeModel : IBridgeModel
    {
        public int Id1 { get; set; }
        public int Id2 { get; set; }
    }

我将桥梁模型中的属性设为通用,这样我就可以将它与另一座桥梁一起使用 table 我拥有多对多关系。网桥 table 只是两列 ID,link 它们各自的 table。在这种情况下 Entity.Id 和 Specialty.Id

这是我将所有信息组合成的模型:

 public class CombinedModel : ICombinedModel
    {
        public int Id { get; set; }
        public int PhysicianId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public List<ISpecialtyModel> Specialties { get; set; }
    }

这是我的数据服务的内部,我在尝试将数据与 Linq 和 Lambda 表达式相结合时遇到困难。

 public async Task<List<IEntityModel>> ReadEntities()
        {
            var entities = await _dataAccess.LoadData<EntityModel, dynamic>("dbo.spEntity_Read", new { }, "SqlDb");
            return entities.ToList<IEntityModel>();
        }

        public async Task<List<ISpecialtyModel>> ReadSpecialties()
        {
            var specialties = await _dataAccess.LoadData<SpecialtyModel, dynamic>("dbo.spSpecialty_Read", new { }, "SqlDb");
            return specialties.ToList<ISpecialtyModel>();
        }

        public async Task<List<IBridgeModel>> ReadEntitySpecialtyBridge()
        {
            var bridge = await _dataAccess.LoadData<BridgeModel, dynamic>("dbo.spEntitySpecialty_Read", new { }, "SqlDb");
            return bridge.ToList<IBridgeModel>();
        }

        public async Task<List<ICombinedModel>> CombineData()
        {
            var entities = await ReadEntities();
            var specialties = await ReadSpecialties();
            var bridge = await ReadEntitySpecialtyBridge();

            //var combined = (from e in entities
            //                join b in bridge on e.Id equals b.Id1
            //                join s in specialties on b.Id2 equals s.Id
            //                select new CombinedModel()
            //                {
            //                    Id = e.Id,
            //                    PhysicianId = e.PhysicianId,
            //                    FirstName = e.FirstName,
            //                    LastName = e.LastName,
            //                    Specialties = new List<ISpecialtyModel>()
            //                });

            var combined = (from e in entities
                            select new CombinedModel
                            {
                                Id = e.Id,
                                PhysicianId = e.PhysicianId,
                                FirstName = e.FirstName,
                                LastName = e.LastName,
                                Specialties = specialties.Where(s =>  )
                            }
                            );

            return combined.ToList<ICombinedModel>();

这就是我卡住的地方。我如何编写此 Linq 查询以将此数据合并到新模型中?

我能够将数据传递到 razor 组件,但我没有正确组合它,这就是我卡住的地方。

我希望有人能对此事有所了解。感谢您抽出宝贵时间查看此内容,非常感谢。

非常感谢, 塞萨尔

如果您想在本地处理(在服务器上执行应该消除从数据库中拉取 bridge 的需要,并且如果 bridge 包含与 [=14] 无关的记录=] 可能会产生大量不必要的数据流量)那么您只需要通过给定实体的正确 bridge 记录过滤 specialties

var combined = (from e in entities
                select new CombinedModel {
                    Id = e.Id,
                    PhysicianId = e.PhysicianId,
                    FirstName = e.FirstName,
                    LastName = e.LastName,
                    Specialties = specialties.Where(s => bridge.Where(b => b.Id1 == e.Id).Select(b => b.Id2).Contains(s.Id)).ToList()
                });

根据 specialtiesentities 的大小,可能值得 pre-process bridge 提高给定实体的访问效率(Where 是 O(n) 所以 specialties.Where x bridge.Where 是 O(n*m)):

var bridgeDict = bridge.GroupBy(b => b.Id1).ToDictionary(bg => bg.Key, bg => bg.Select(b => b.Id2).ToHashSet());
var combined = (from e in entities
                let eBridge = bridgeDict[e.Id]
                select new CombinedModel {
                    Id = e.Id,
                    PhysicianId = e.PhysicianId,
                    FirstName = e.FirstName,
                    LastName = e.LastName,
                    Specialties = specialties.Where(s => eBridge.Contains(s.Id)).ToList()
                });