问题描述
您好,我有一个名为 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>();
}