如何在 Entity Framework Core 中调用带有多个表联接的存储过程?

2024-01-03

我必须调用一个从多个表中选择记录的存储过程。

我已尝试以下代码,但它为实体类以外的其他表中的列返回 null。

private async Task<IEnumerable<TEntity>> InvokeStoredProcedureAsync(string input = "")
{
    var storedProcedureName = "sp_BulkSelect";

    using (var db = new MyDbContext(_options))
    {
        var result = await db.Set<TEntity>().FromSql(storedProcedureName + " @inputIds", new SqlParameter("inputIds", input)).ToListAsync();
        return result;
    }
}

存储过程:

SELECT 
    [MainTable].[Id],
    [Table1Id],
    [Table2Id],
    [MainTable].[Table1Code],
    [Table2].[Table2Code]
FROM
    [MainTable] [MainTable]
LEFT JOIN 
    [Table1] [Table1] ON [MainTable].Table1Id = [Table1].[Id]
LEFT JOIN 
    [Table2] [Table2] ON [MainTable].[Table2Id] = [Table2].[Id];

MainTable class:

[Table("MainTable")]
public class MainTable : FullAuditedEntity
{

    [ForeignKey("Table1Id")]
    public virtual Table1 Table1 { get; set; }
    public virtual int Table1Id { get; set; }

    [ForeignKey("Table2Id")]
    public virtual Table2 Table2 { get; set; }
    public virtual int? Table2Id { get; set; }      

}

所以当我调用这个存储过程时,Table1Code and Table2Code返回值中缺失。

我尝试添加以下代码MainTable类,但它也不起作用。

[NotMapped]
public virtual string Table2Code { get; set; }

[NotMapped]
public virtual string Table1Code { get; set; }

然后我删除了[NotMapped]从属性和添加的迁移来看,在这种情况下,它返回正确的值。但它会在 MainTable 中添加两列。这真的是一个BAD design.

所以我的问题是如何从 Entity Framework Core 中的存储过程中的多个表中选择列。

我正在使用 EF Core 2.0。

我认为必须有某种方法使用 Entity 调用存储过程,然后将其映射到任何类,因为使用联接从多个表中选择列是一个非常基本的要求。

我尝试过类似的solution https://stackoverflow.com/a/27807174/6527049,但它给出了编译错误。

“DatabaseFacade”不包含“SqlQuery”的定义,并且没有 扩展方法“SqlQuery”接受类型的第一个参数 可以找到“DatabaseFacade”(您是否缺少 using 指令或 装配参考?)


从存储过程获取数据的完整思路如下:

  1. 您需要添加一个与过程选择查询具有相同属性的实体。
  2. 将实体添加到您的DbContext并创建迁移。更改中的代码Up() and Down()迁移的方法,以便在数据库中创建过程。
  3. 现在使用FromSql()方法获取正常实体数据的数据。

这是一些可以指导您的代码。假设您的应用程序域中有以下实体:

  1. Student
  2. Parent
  3. 学校班级
  4. Section
  5. 注册

向上迁移方法

protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "StudentDetails");

        migrationBuilder.Sql(
            @"create proc GetStudentDetail
            @ssid int,
            @sectionId int = null
            as
            select Id, name, Gender, RollNumber, Status, Type,
            FatherName, FatherContact, SchoolClass, Section,
            SsId, SectionId, EnrollmentId
            from 
            (
                SELECT stu.Id, stu.name, stu.Gender, en.RollNumber, en.Status, en.Type,
                p.FatherName, p.FatherContact, sc.Name as SchoolClass, sec.Name as Section,
                ss.SessionId as SsId, sec.Id as SectionId, en.Id as EnrollmentId,
                en.EntryDate, row_number() over (partition by studentid order by en.entrydate desc) as rowno
                from SchoolSessions ss
                join SchoolClasses sc on ss.SessionId = sc.ssid
                join Sections sec on sc.Id = sec.ClassId
                join Enrollments en on sec.id = en.SectionId
                join Students stu on en.StudentId = stu.Id
                join parents p on stu.ParentId = p.Id 
                where ss.SessionId = @ssid 
            ) A
            where rowno = 1 and
            (SectionId = @sectionId or @sectionId is null)"
            );
    }

向下迁移方法

protected override void Down(MigrationBuilder migrationBuilder)
    {

        migrationBuilder.Sql("drop proc GetStudentDetail");

        migrationBuilder.CreateTable(
            name: "StudentDetails",
            columns: table => new
            {
                Id = table.Column<int>(nullable: false)
                    .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                EnrollmentId = table.Column<int>(nullable: false),
                FatherContact = table.Column<string>(nullable: true),
                FatherName = table.Column<string>(nullable: true),
                Gender = table.Column<int>(nullable: false),
                Name = table.Column<string>(nullable: true),
                RollNumber = table.Column<string>(nullable: true),
                SchoolClass = table.Column<string>(nullable: true),
                Section = table.Column<string>(nullable: true),
                SectionId = table.Column<int>(nullable: false),
                SsId = table.Column<int>(nullable: false),
                Status = table.Column<int>(nullable: false),
                Type = table.Column<int>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_StudentDetails", x => x.Id);
            });
    }

假实体:该实体中的所有属性均来自上述实体。你可以称其为假实体。

public class StudentDetail
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Gender Gender { get; set; }
    public string RollNumber { get; set; }
    public StudentStatus Status { get; set; }
    public StudentType Type { get; set; }
    public string FatherName { get; set; }
    public string FatherContact { get; set; }
    public string SchoolClass { get; set; }
    public string Section { get; set; }
    public int SsId { get; set; }
    public int SectionId { get; set; }
    public int EnrollmentId { get; set; }
}

服务层获取数据

public IEnumerable<StudentDetail> GetStudentDetails(int ssid)
    {
        var ssidParam = new SqlParameter("@ssid", ssid);
        var result = _appDbContext.StudentDetails.FromSql("exec GetStudentDetail @ssid", ssidParam).AsNoTracking().ToList();
        return result;
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Entity Framework Core 中调用带有多个表联接的存储过程? 的相关文章

随机推荐

  • 射线与平面的交点坐标

    我有一条射线和一架飞机 射线与平面相交 我想知道在哪里 如何获得该交点的世界坐标 我的特殊情况是 我将屏幕坐标取消投影到相机并创建光线 该平面是场景的地面 var vector new THREE Vector3 mousePosition
  • 如何在不刷新整个页面的情况下让 Grunt/Watch/LiveReload 重新加载 Sass/CSS?

    到目前为止 我已经让一切按照我想要的方式工作 即监视我想要的所有文件并在发生更改时刷新 除了我希望能够对 Sass CSS 进行修改并刷新它在没有页面加载的浏览器中 这不是什么大问题 但有时我会在进行一些页面交互后尝试修改某些内容的样式 并
  • 使用“data.table”根据变量获取子组的第一个

    考虑一个由分组变量组成的数据集 这里id 和一个有序变量 这里date df lt data frame id rep 1 2 2 date 4 1 id date 1 1 4 2 2 3 3 1 2 4 2 1 我想知道最简单的方法是什么
  • iPhone Web App - 在 iOS8 中停止身体弹跳/滚动

    是的 我知道 这个问题之前已经被问过一千次了 感谢你们所有人 我终于找到了一个解决方案 最终在 更新到 iOS 8 后 似乎没有任何效果 iOS7 中最适合我的是什么 Css html body scrollable overflow au
  • mysql中选择部分表列数据

    我有一个包含 2000 个条目的 照片 表 该表有一列名为photo note其中包含以下格式但具有不同放大值的数据 Magnification 30x The resolution varies depending on 我需要选择以 分
  • CTE(通用表表达式)与临时表或表变量,哪个更快?

    CTE 通用表表达式 与Temp tables or Table variables 哪个更快 正如我在评论中已经说过的 这取决于 它确实取决于您的查询 您的数据 有多少 它是什么类型 等等 不过 需要记住一些要点 CTE 是仅对下一条语句
  • 编译 jitsi 项目时,转换为 Dalvik 格式失败,出现错误 1

    我正在尝试编译并运行该项目https github com jitsi jitsi android https github com jitsi jitsi android在 Eclipse 上通过导入 我已成功导入项目 添加了外部 Jar
  • Shopify 结账中的脚本标签

    我正在考虑为 Shopify 开发一款应用程序 该应用程序将为商店的结帐页面添加功能 如果用户不必将代码复制并粘贴到文件中 那将是理想的选择 因此我正在考虑使用 ScriptTag API http api shopify com scri
  • 为什么内部调用内的 lapply 与内部调用内的变量赋值不同?

    考虑 notBroken lt within mtcars gear lt as factor gear cyl lt as factor cyl str notBroken 我们的输出 gt str notBroken data fram
  • 将 SQL 中的 CASE 表达式转换为 SSIS 中的派生列 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions CASE WHEN CHARINDE
  • 禁用 Cypress 自动滚动

    我正在测试我的应用程序 我有很长的侧边菜单 并且我有这样的代码 cy get tab click force true 自动滚动发生在获取和单击之间 然后选定的选项卡不可见 因为顶部菜单的位置已固定 我找到了很多解决方案 但没有一个有效 到
  • 如何在 Swift iOS 应用程序中添加 Google Drive API?

    我有一个用 Swift 编写的应用程序 它已经使用了 SwiftyDropbox API 我用 cocoapods 安装了 SwiftyDropbox use frameworks 关键词 现在 当我添加这个 pod 时 Google AP
  • 在 WooCommerce 3+ 中向订单添加自定义字段

    在 WooCommerce 中 我想添加一个新的自定义字段来订单详细信息 现在我可以使用下面的代码创建一个新的自定义字段 referenceNumber 并在其中添加 ordercreated 值 update post meta orde
  • SpriteKit场景切换时的内存问题

    Ok so awhile back in testing I had a random crash with no error and I have no clue why So i went into analyze things and
  • npm 如何/为什么建议不要以 root 身份运行?

    简而言之 首先 为什么npm http npmjs org 建议它只能以非 root 身份运行 我非常不相信其他所有包管理器 apt yum gem pacman 要求 sudo 是错误的 其次 当我遵循他们的建议 并运行npm insta
  • :this 在 Ruby on Rails 中意味着什么?

    我是 Ruby 和 Ruby on Rails 世界的新手 我已经阅读了一些指南 但我在使用以下语法时遇到了一些问题 我认为使用 conditionRuby 中使用语法来定义具有某种访问器的类属性 例如 class Sample attr
  • 将 Flutter 小部件定位到屏幕外

    正如标题所提到的 我试图将我的小部件放置在屏幕之外 目前我已经设法将小部件图像偏移到屏幕之外 但这不是我期望的结果 屏幕外的图像在状态栏上仍然可见 这就是它的样子 这就是我期望的样子 用 adobe XD 设计 Widget build B
  • Rails 3 的 A/B 框架?

    有没有像 ABingo 或 Vanity 这样的东西可以在 Rails 3 中运行 我知道有 Google 网站优化器和可视化网站优化器 但我需要更多的功能来确定显示的内容以及跟踪的内容 而这些功能超出了它们的能力 如果没有 我什至会考虑相
  • 为什么简单的 Dockerfile 给出“权限被拒绝”?

    我正在学习将 Docker 与 ROS 结合使用 我对以下错误消息感到惊讶 FROM ros kinetic robot xenial create non root user ENV USERNAME ros RUN adduser in
  • 如何在 Entity Framework Core 中调用带有多个表联接的存储过程?

    我必须调用一个从多个表中选择记录的存储过程 我已尝试以下代码 但它为实体类以外的其他表中的列返回 null private async Task