EF Core存储过程的不同返回结果

时间:2019-05-12 07:55:43

标签: c# entity-framework-core

我有这个存储过程

CREATE PROCEDURE [dbo].[GetBooksByAuthor2]
AS
    SELECT 
        books.Id, authors.Name AS Author, books.Name AS Book 
    FROM
        dbo.Authors authors
    INNER JOIN 
        dbo.AuthorsBooks authorsBooks ON authors.Id = authorsBooks.AuthorId
    INNER JOIN 
        dbo.Books books ON books.Id = authorsBooks.BookId
GO

在SQL Server Management Studio中,结果如下:

Id| Author       | Book
--+--------------+----------
1 | FirstAuthor  | GoodBook1
2 | FirstAuthor  | GoodBook2
3 | FirstAuthor  | GoodBook3
1 | SecondAuthor | GoodBook1
3 | SecondAuthor | GoodBook3 

在EF Core中,我为存储过程添加了一个视图模型

public class BookViewModel
{
    [Key]
    public int Id { get; set; }

    public string Author { get; set; }
    public string Book { get; set; }
}

并且我还向上下文类添加了类似的内容:

public partial class StrangeContext : DbContext
{
     public virtual DbSet<BookViewModel> Books2 { get; set; }
}

然后我在控制器操作中调用它

[HttpGet]
public JsonResult GetAuthors()
{
    var result = db.Books2.FromSql("GetBooksByAuthor2").ToList();
    return new JsonResult(result);
}

Json的结果类似于

[
    { "id": 1, "author":"FirstAuthor", "book":"GoodBook1"},
    { "id": 2, "author":"FirstAuthor", "book":"GoodBook2"},
    { "id": 3, "author":"FirstAuthor", "book":"GoodBook3"}, 
    { "id": 1, "author":"FirstAuthor", "book":"GoodBook1"}, 
    { "id": 3, "author":"FirstAuthor", "book":"GoodBook3"}
]

我做错了什么?错误的ViewModel? SecondAuthor在哪里?

3 个答案:

答案 0 :(得分:4)

您将Id中的BookViewModel定义为 Key ,因此,如果使用{{1}查询“ FirstAuthor”,则Entity Framework会第一次缓存}( 1 )。第二次遇到Id 1时,它将使用当前上下文并根据缓存的值填充实体。

这里的问题是您模棱两可的模型。 IdFirstAuthor如何都具有SecondAuthor = 1。

您可以在模型中删除 Key 属性,但这可能会导致混乱,无论您在何处显示这些结果,并且一旦要保存任何这些实体,都将得到无法预测的结果。

您也可以尝试Id,但我强烈建议您这样做,因为一旦您尝试跟踪或保存更改,就会遇到麻烦。而是调整存储过程以为唯一行返回唯一的AsNotracking()

答案 1 :(得分:1)

您已经在Id类中将BookViewModel定义为键,但是您要传递非唯一值:

authorsBooks.Id添加到您的SQL查询中,并将其传递给您班级的[Key],并定义另一个字段以在您的查询和班级中显示BookId

代码如下:

public class BookViewModel
{
    [Key]
    public int Id { get; set; }

    public string Author { get; set; }

    public int BookId { get; set; }

    public string Book { get; set; }
}

您最好这样编写程序:

ALTER PROCEDURE [dbo].[GetBooksByAuthor2]
AS
    SELECT 
        AB.Id AS id, B.Id AS bookId, 
        A.[Name] AS author, B.[Name] AS book 
    FROM
        dbo.AuthorsBooks AS AB
    INNER JOIN 
        dbo.Books B ON AB.BookId = B.Id
    INNER JOIN 
        dbo.Authors A ON A.Id = AB.AuthorId
GO

答案 2 :(得分:-1)

由于Sp返回有多个具有相同ID的条目。 对于上面给定的表实体,可以在DbContext注册中使用DbQuery而不是使用DbSet。使用将获取数据。 Nite:DbQuery不支持键,因为任何属性都会删除ID的键属性。