是否可以使用带有内部连接的 ef core 5 运行 原始 sql 并将数据具体化为 class?
is it possible to run a raw sql using ef core 5 with inner join and materialize the data to a class?
public class UserDto
{
public int Id {get; set;}
public string Name {get; set;}
public string Email {get; set;}
public string Username {get; set;}
}
//代码第一个实体class
public class User
{
public int Id {get; set;}
public string Username {get; set;}
}
//代码第一个实体class
public class Profile
{
public string Name {get; set;}
public string Email {get; set;}
}
// 我想做这样的事情
List<UserDto> userDto = context.Database
.FromSqlRaw<List<UserDto>>("SELECT u.Id, u.Username, p.Name, p.Email FROM dbo.User u
INNER JOIN dbo.Profile p on p.UserId = u.id
").ToList();
我通常会使用视图,以便能够通过迁移处理所有 RawSql 查询。
为此,您可以在创建主要实体和迁移后执行以下操作。
为结果模型新建Class:
public class JoinedResult
{
public int UserId { get; set; }
public string Username { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
通过 运行 add-migration 命令创建空迁移,例如:
add-migration JoinedResultsView
然后像这样更新迁移:
public partial class JoinedResultsView : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(@"CREATE VIEW JoinedResults
AS
SELECT u.UserId, u.Username, p.Name, p.Email
FROM dbo.Users AS u INNER JOIN
dbo.Profiles AS p ON p.UserId = u.UserId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("DROP VIEW JoinedResults");
}
}
最后一步是使用配置将视图映射到实体 class:
public class JoinedResultConfiguration :IEntityTypeConfiguration<JoinedResult>
{
public void Configure(EntityTypeBuilder<JoinedResult> builder)
{
builder.ToView("JoinedResults");
builder.HasNoKey();
builder.Property(p => p.Name).HasColumnName("Name");
builder.Property(p => p.Email).HasColumnName("Email");
builder.Property(p => p.UserId).HasColumnName("UserId");
builder.Property(p => p.Username).HasColumnName("Username");
}
}
然后将配置添加到 DbContext:
public class MyDbContext : DbContext
{
public DbSet<Profile> Profiles { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<JoinedResult> JoinedResults { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseSqlServer($"data source=.;initial catalog=TheDb;Integrated Security=True");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new JoinedResultConfiguration());
}
}
就是这样。
不仅你可以在你的代码中得到这样的查询结果:
var queryResult = cntx.JoinedResults.ToList();
但您还可以在此基础上添加 linq 查询:
var x = cntx.JoinedResults.OrderBy(x => x.Name).FirstOrDefault(x => x.Name.Contains("MA"));
这也是一种非常有用的方法,可以提取出大查询和慢查询的公共部分并将它们重写为 Sql 视图,然后在它们之上添加 linq 查询以用于 non-common部分。
玩得开心;)
public class UserDto
{
public int Id {get; set;}
public string Name {get; set;}
public string Email {get; set;}
public string Username {get; set;}
}
//代码第一个实体class
public class User
{
public int Id {get; set;}
public string Username {get; set;}
}
//代码第一个实体class
public class Profile
{
public string Name {get; set;}
public string Email {get; set;}
}
// 我想做这样的事情
List<UserDto> userDto = context.Database
.FromSqlRaw<List<UserDto>>("SELECT u.Id, u.Username, p.Name, p.Email FROM dbo.User u
INNER JOIN dbo.Profile p on p.UserId = u.id
").ToList();
我通常会使用视图,以便能够通过迁移处理所有 RawSql 查询。
为此,您可以在创建主要实体和迁移后执行以下操作。
为结果模型新建Class:
public class JoinedResult
{
public int UserId { get; set; }
public string Username { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
通过 运行 add-migration 命令创建空迁移,例如:
add-migration JoinedResultsView
然后像这样更新迁移:
public partial class JoinedResultsView : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(@"CREATE VIEW JoinedResults
AS
SELECT u.UserId, u.Username, p.Name, p.Email
FROM dbo.Users AS u INNER JOIN
dbo.Profiles AS p ON p.UserId = u.UserId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("DROP VIEW JoinedResults");
}
}
最后一步是使用配置将视图映射到实体 class:
public class JoinedResultConfiguration :IEntityTypeConfiguration<JoinedResult>
{
public void Configure(EntityTypeBuilder<JoinedResult> builder)
{
builder.ToView("JoinedResults");
builder.HasNoKey();
builder.Property(p => p.Name).HasColumnName("Name");
builder.Property(p => p.Email).HasColumnName("Email");
builder.Property(p => p.UserId).HasColumnName("UserId");
builder.Property(p => p.Username).HasColumnName("Username");
}
}
然后将配置添加到 DbContext:
public class MyDbContext : DbContext
{
public DbSet<Profile> Profiles { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<JoinedResult> JoinedResults { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseSqlServer($"data source=.;initial catalog=TheDb;Integrated Security=True");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new JoinedResultConfiguration());
}
}
就是这样。
不仅你可以在你的代码中得到这样的查询结果:
var queryResult = cntx.JoinedResults.ToList();
但您还可以在此基础上添加 linq 查询:
var x = cntx.JoinedResults.OrderBy(x => x.Name).FirstOrDefault(x => x.Name.Contains("MA"));
这也是一种非常有用的方法,可以提取出大查询和慢查询的公共部分并将它们重写为 Sql 视图,然后在它们之上添加 linq 查询以用于 non-common部分。
玩得开心;)