Ef Core - 使用Automapper从keyless View获取数据
Ef Core - Use Automapper to get data from keyless View
我需要知道是否可以使用 Automapper 从数据库视图映射 DTO 属性。或者可能在 DbContext 模型配置中。假设我有一个包含其他相关数据的视图的业务目的,但为了简洁起见,我将 classes 简化为
相关的 Nugets
- EF 核心 v3.1.7
- AutoMapper v10.0.0
我有一个实体
public class Foo {
public int Id { get; set; }
public string Name { get; set; }
}
我有一个无钥匙视图
public class BarVW {
public int FooId { get; set; }
public string FooName { get; set; }
}
视图是在 DB Initializer 中构建的 class
context.Database.ExecuteSqlRaw(
@"CREATE OR REPLACE VIEW v_Bar AS
select
f.Id as FooId,
f.[Name] as FooName
from
Foo f
-- where some logic that makes a Foo appear in view"
);
然后将视图分配给DbContext中的一个DbSetclass
modelBuilder.Entity<BarVW>(eb =>
{
eb.HasNoKey();
eb.ToView("v_Bar");
});
public DbSet<BarVW> BarVW { get; set; }
在我的 FooDto 中,我的实体 class 需要一个额外的 属性,它将表明这个 Foo 存在于我的数据库视图中 v_Bar
public class FooDto {
public int Id { get; set; }
public string Name { get; set; }
public bool IsBar { get; set; }
}
对于 Automapper 配置,我有以下配置,但我不知道有一种方法可以将我的 dto IsBar
属性 从 BarVW DbSet
CreateMap<Foo, FooDto>()
.ForMember(dto => dto.IsBar, opt => ??? ); // don't know what to put here
实现所需功能的一种简单方法是引入导航 属性(例如 Bars
)并在映射配置中使用它(例如 opt.MapFrom(src => src.Bars.Any())
)。
这是一个完整的示例控制台程序,演示了这种方法:
using System.Diagnostics;
using System.Linq;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public BarVW Bar { get; set; }
}
public class BarVW
{
public int FooId { get; set; }
public string FooName { get; set; }
public Foo Foo { get; set; }
}
public class Context : DbContext
{
public virtual DbSet<Foo> Foo { get; set; }
public virtual DbSet<BarVW> BarVW { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
@"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So63850736")
.UseLoggerFactory(LoggerFactory.Create(b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Foo>()
.HasData(
new Foo {Id = 1, Name = "Fo"},
new Foo {Id = 2, Name = "Foo"},
new Foo {Id = 3, Name = "Fooo"});
modelBuilder.Entity<BarVW>(
eb =>
{
eb.HasKey(e => e.FooId);
eb.ToView("v_Bar");
eb.HasOne(e => e.Foo)
.WithOne(e => e.Bar)
.HasForeignKey<BarVW>(e => e.FooId);
});
}
}
public class FooDto
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsBar { get; set; }
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
context.Database.ExecuteSqlRaw(
@"CREATE VIEW [v_Bar] AS
select
f.[Id] as [FooId],
f.[Name] as [FooName]
from
[Foo] f
where
f.[Id] >= 1 and f.[Id] <= 2"
);
var config = new MapperConfiguration(
cfg => cfg
.CreateMap<Foo, FooDto>()
.ForMember(dto => dto.IsBar, opt => opt.MapFrom(src => src.Bar != null)));
var result = context.Foo
.ProjectTo<FooDto>(config)
.ToList();
Debug.Assert(result.Count == 3);
Debug.Assert(result.Count(dto => dto.IsBar) == 2);
}
}
}
为查询生成的 SQL 如下所示:
SELECT [f].[Id], CASE
WHEN [v].[FooId] IS NOT NULL THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [IsBar], [f].[Name]
FROM [Foo] AS [f]
LEFT JOIN [v_Bar] AS [v] ON [f].[Id] = [v].[FooId]
您可以 运行 使用 .NET Fiddle 的示例代码。
我需要知道是否可以使用 Automapper 从数据库视图映射 DTO 属性。或者可能在 DbContext 模型配置中。假设我有一个包含其他相关数据的视图的业务目的,但为了简洁起见,我将 classes 简化为
相关的 Nugets
- EF 核心 v3.1.7
- AutoMapper v10.0.0
我有一个实体
public class Foo {
public int Id { get; set; }
public string Name { get; set; }
}
我有一个无钥匙视图
public class BarVW {
public int FooId { get; set; }
public string FooName { get; set; }
}
视图是在 DB Initializer 中构建的 class
context.Database.ExecuteSqlRaw(
@"CREATE OR REPLACE VIEW v_Bar AS
select
f.Id as FooId,
f.[Name] as FooName
from
Foo f
-- where some logic that makes a Foo appear in view"
);
然后将视图分配给DbContext中的一个DbSetclass
modelBuilder.Entity<BarVW>(eb =>
{
eb.HasNoKey();
eb.ToView("v_Bar");
});
public DbSet<BarVW> BarVW { get; set; }
在我的 FooDto 中,我的实体 class 需要一个额外的 属性,它将表明这个 Foo 存在于我的数据库视图中 v_Bar
public class FooDto {
public int Id { get; set; }
public string Name { get; set; }
public bool IsBar { get; set; }
}
对于 Automapper 配置,我有以下配置,但我不知道有一种方法可以将我的 dto IsBar
属性 从 BarVW DbSet
CreateMap<Foo, FooDto>()
.ForMember(dto => dto.IsBar, opt => ??? ); // don't know what to put here
实现所需功能的一种简单方法是引入导航 属性(例如 Bars
)并在映射配置中使用它(例如 opt.MapFrom(src => src.Bars.Any())
)。
这是一个完整的示例控制台程序,演示了这种方法:
using System.Diagnostics;
using System.Linq;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public BarVW Bar { get; set; }
}
public class BarVW
{
public int FooId { get; set; }
public string FooName { get; set; }
public Foo Foo { get; set; }
}
public class Context : DbContext
{
public virtual DbSet<Foo> Foo { get; set; }
public virtual DbSet<BarVW> BarVW { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
@"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So63850736")
.UseLoggerFactory(LoggerFactory.Create(b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Foo>()
.HasData(
new Foo {Id = 1, Name = "Fo"},
new Foo {Id = 2, Name = "Foo"},
new Foo {Id = 3, Name = "Fooo"});
modelBuilder.Entity<BarVW>(
eb =>
{
eb.HasKey(e => e.FooId);
eb.ToView("v_Bar");
eb.HasOne(e => e.Foo)
.WithOne(e => e.Bar)
.HasForeignKey<BarVW>(e => e.FooId);
});
}
}
public class FooDto
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsBar { get; set; }
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
context.Database.ExecuteSqlRaw(
@"CREATE VIEW [v_Bar] AS
select
f.[Id] as [FooId],
f.[Name] as [FooName]
from
[Foo] f
where
f.[Id] >= 1 and f.[Id] <= 2"
);
var config = new MapperConfiguration(
cfg => cfg
.CreateMap<Foo, FooDto>()
.ForMember(dto => dto.IsBar, opt => opt.MapFrom(src => src.Bar != null)));
var result = context.Foo
.ProjectTo<FooDto>(config)
.ToList();
Debug.Assert(result.Count == 3);
Debug.Assert(result.Count(dto => dto.IsBar) == 2);
}
}
}
为查询生成的 SQL 如下所示:
SELECT [f].[Id], CASE
WHEN [v].[FooId] IS NOT NULL THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [IsBar], [f].[Name]
FROM [Foo] AS [f]
LEFT JOIN [v_Bar] AS [v] ON [f].[Id] = [v].[FooId]
您可以 运行 使用 .NET Fiddle 的示例代码。