微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Entity Framework Core Code First 尝试将存储过程添加为表

如何解决Entity Framework Core Code First 尝试将存储过程添加为表

您好,我有一个名为 dbo.GetFolderDocumentsHierarchy 的存储过程,它直接映射到以下类。

public class DocumentDto:IModel
{
    public int FolderId { get; set; }
    [CanBeNull]
    public int Id { get; set; }
    public string FolderName { get; set; }
    public string DocumentName { get; set; }
    public string ParentName { get; set; }
    public int? ParentId { get; set; }
}

我已经像这样将它添加到我的上下文中。

builder.Query<DocumentDto>();

我可以补充一点,我称之为:

var dtos = await _context
                .Set<DocumentDto>()
                .FromsqlRaw("EXEC dbo.GetFolderDocumentsHierarchy @Skip,@Take,@UserId",sqlParameters)
                .ToListAsync();

现在来谈谈我的问题,每次我创建一个新的迁移时,它都会将以下代码添加到迁移和快照中。

            migrationBuilder.CreateTable(
            name: "DocumentDto",columns: table => new
            {
                FolderId = table.Column<int>(nullable: false),Id = table.Column<int>(nullable: false),FolderName = table.Column<string>(nullable: true),DocumentName = table.Column<string>(nullable: true),ParentName = table.Column<string>(nullable: true),ParentId = table.Column<int>(nullable: true)
            },constraints: table =>
            {
            });

在快照中:

            modelBuilder.Entity("Models.Dtos.DocumentDto",b =>
            {
                b.Property<string>("DocumentName")
                    .HasColumnType("nvarchar(max)");

                b.Property<int>("FolderId")
                    .HasColumnType("int");

                b.Property<string>("FolderName")
                    .HasColumnType("nvarchar(max)");

                b.Property<int>("Id")
                    .HasColumnType("int");

                b.Property<int?>("ParentId")
                    .HasColumnType("int");

                b.Property<string>("ParentName")
                    .HasColumnType("nvarchar(max)");

                b.ToTable("DocumentDto");
            });

我怎样才能让它不再添加到迁移中?

编辑: 添加完整上下文。

    public virtual DbSet<ApplicationUser> ApplicationUsers { get; set; }
    public virtual DbSet<Appointment> Appointments { get; set; }
    public virtual DbSet<Campaign> Campaigns { get; set; }
    public virtual DbSet<Contact> Contacts { get; set; }
    public virtual DbSet<Customer> Customers { get; set; }
    public virtual DbSet<Deal> Deals { get; set; }
    public virtual DbSet<Document> Documents { get; set; }
    public virtual DbSet<Folder> Folders { get; set; }
    public virtual DbSet<Group> Groups { get; set; }
    public virtual DbSet<GroupDocument> GroupDocuments { get; set; }
    public virtual DbSet<UserDocument> UserDocuments { get; set; }
    public virtual DbSet<UserGroup> UserGroups { get; set; }
    public virtual DbSet<UserFolder> UserFolders { get; set; }
    public virtual DbSet<UserTask> UserTasks { get; set; }
    public virtual DbSet<Opportunity> Opportunities { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        builder.Entity<UserTask>()
            .HasIndex(x => x.OwnerId);

        builder.Entity<Group>()
            .HasMany(x => x.Campaigns)
            .WithOne(x => x.Group);

#pragma 警告禁用 618 builder.Query(); #pragma 警告恢复 618

        builder.Entity<GroupDocument>()
            .HasKey(gd => new { gd.GroupId,gd.DocumentId });
        builder.Entity<UserDocument>()
            .HasKey(x => new {x.UserId,x.DocumentId});
        builder.Entity<UserFolder>()
            .HasKey(x => new {x.UserId,x.FolderId});

    }

解决方法

Ivan Stoev 的回答 here 中提到了主要技巧,即始终添加 ToView 映射语句。即使没有景色。唯一的区别是 EF core 5 不支持 .ToView(null),您必须输入一些字符串。

一般来说,您的选择是:

1

modelBuilder.Entity<DocumentDto>
( eb => 
    {
        eb.HasNoKey();
        eb.ToSqlQuery("EXEC StoredProcedureWithoutParameters");
        // Or: eb.ToSqlQuery("SELECT ... FROM ... ");
        eb.ToView("dummy view name"); // To prevent table creation.
    }
);

或者,当存在 视图时,您将 DTO 映射到:

2

modelBuilder.Entity<DocumentDto>
( eb => 
    {
        eb.HasNoKey();
        eb.ToView("MyView"); // Map to existing view
    }
);

或者,只是将 DTO 映射为无键实体:

3

modelBuilder.Entity<DocumentDto>
( eb => 
    {
        eb.HasNoKey();
        eb.ToView("Dummy view name"); // To prevent table creation
    }
);

使用选项 3 时,您应该使用已有的代码填充 DTO,例如:

context.Set<DocumentDto>()
       .FromSqlRaw("EXEC dbo.GetFolderDocumentsHierarchy @Skip,@Take,@UserId",sqlParameters)

据我所知,这是使用带参数的存储过程的唯一方法。也许有一些奇特的方法可以使用选项 1 并使 EF 将 Where 语句的谓词传递给原始 SQL 查询,但我对此表示怀疑。

我认为最好的选择是将 DTO 映射到真实视图(选项 2,您现在执行,正如您在评论中提到的那样),因为在这种情况下,IQueryable 可以通过 { {1}} 语句。此外,它可以以生成一条 SQL 语句的方式进行组合,从而允许数据库引擎查询优化器计算整体查询计划。当然,这只有在存储过程代码可以转换为视图时才有可能。

,

您应该可以像这样忽略 OnModelCreating 中的类:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Ignore<DocumentDto>();
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。