我有以下实体类:
namespace Entities
{
public abstract class EntityBase
{
public EntityBase()
{
Id = Guid.NewGuid();
}
public Guid Id { get; set; }
}
}
public class Name : EntityBase
{
public DateTime LastUpdatedTime { get; set; }
public string Name { get; set; }
public Package Package { get; set; }
}
public class Owner : EntityBase
{
public DateTime LastUpdatedTime { get; set; }
public Guid ObjectId { get; set; }
public List<Package> Packages { get; set; }
}
public class Status : EntityBase
{
public string Name { get; set; }
public int SortPriority { get; set; }
}
public class Package : EntityBase
{
public Package()
{
}
public Guid? RequestorId { get; set; }
public string Requestor { get; set; }
public Name Name { get; set; }
public List<Owner> Owners { get; set; }
public Status StatusDetails { get; set; }
}
我有以下模型类:
namespace Models
{
public abstract class ModelBase
{
public Guid Id { get; set; }
}
}
public class Name : ModelBase
{
public DateTime LastUpdatedTime { get; set; }
public string Name { get; set; }
public Package Package { get; set; }
}
public class Owner : ModelBase
{
public DateTime LastUpdatedTime { get; set; }
public Guid ObjectId { get; set; }
public List<Package> Packages { get; set; }
}
public class Status : ModelBase
{
public string Name { get; set; }
public int SortPriority { get; set; }
}
public class Package : ModelBase
{
public Package()
{
}
public Guid? RequestorId { get; set; }
public string Requestor { get; set; }
public Name Name { get; set; }
public List<Owner> Owners { get; set; }
public Status StatusDetails { get; set; }
}
这是 DbContext 类:
using Entities;
public class WriteContext : DbContext
{
public DbSet<Package> Packages { get; set; } = null!;
public DbSet<Name> Names { get; set; }
public DbSet<Owner> Owners { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Package>().Property(t => t.Id)
.ValueGeneratedOnAdd()
.HasDefaultValueSql("NEWSEQUENTIALID()");
modelBuilder.Entity<Package>()
.HasOne(s => s.StatusDetails)
.WithOne()
.HasForeignKey<Package>(x => x.Status)
.HasPrincipalKey<Status>(x => x.Name)
.IsRequired(false)
.OnDelete(DeleteBehavior.NoAction);
modelBuilder.Entity<Status>()
.ToTable("Statuses");
modelBuilder.Entity<JobNotification>().Property(t => t.Id)
modelBuilder.Entity<Package>()
.HasOne(package => package.Name)
.WithOne(name => name.Package)
.HasForeignKey<Name>(name => name.Id);
modelBuilder.Entity<Package>()
.HasMany(package => package.Owners)
.WithMany(owner => owner.Packages);
modelBuilder.Entity<Owner>().Property(owner => owner.Id)
.ValueGeneratedOnAdd()
.HasDefaultValueSql("NEWSEQUENTIALID()");
modelBuilder.Entity<Owner>()
.HasIndex(owner => owner.ObjectId);
modelBuilder.Entity<Name>()
.HasIndex(name => name.Name);
}
public WrietContext(DbContextOptions<WriteContext> options)
: base(options)
{
}
}
这是存储库类:
using Models;
public class DatabasePackagesRepository : RepositoryBase<Entities.Package, Models.Package>, IDatabasePackagesRepository
{
private readonly WriteContext _writeContext;
public DatabasePackagesRepository(WriteContext writeContext)
: base(writeContext)
{
_readContext = readContext;
}
public override Entities.Package MapModelToEntity(Models.Package model)
{
return new Entities.Package
{
Id = model.Id,
RequestorId = model.RequestorId,
Requestor = model.Requestor
};
}
public override Models.Package MapEntityToModel(Entities.Package entity)
{
return new Models.Package
{
Id = entity.Id,
RequestorId = entity.RequestorId,
Requestor = entity.Requestor
};
}
public async Task<List<Models.Package>> GetPackagesAsync()
{
var entities = await _readContext.Packages.ToListAsync();
return entities.Select(MapEntityToModel).ToList();
}
运行此程序时,我看到错误
System.InvalidOperationException:LINQ 表达式 'DbSet() .Where(s => DatabasePackagesRepository.MapEntityToModel(s).Owners .Any(o => o.ObjectId == __Parse_0))' 无法翻译。以可翻译的形式重写查询,或者通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用来显式切换到客户端评估。
如何更新 MapEntityToModel 以包含所有者、名称和状态详细信息?
快速回答:使用已经支持 EF
IQueryable
的映射器,包括 Automapper、Mapperly 和 Mapster 等。
例如使用 Automapper:
public async Task<List<Models.Package>> GetPackagesAsync()
{
var config = new MapperConfiguration(cfg => cfg.CreateMap<Entities.Package, Models.Package>());
var models = await _readContext.Packages
.ProjectTo<Entities.Package>(config)
.ToListAsync();
return models;
}
我强烈建议避免像这样的通用存储库模式。将 EF 抽象到这种程度会导致代码效率极低,从而导致难以使用、速度缓慢和内存使用过多。当存储库返回适合所有场合而不是实体的“模型”时,您最终得到的模型是它们映射到的实体的严格一对一副本。既然如此,他们的目的是什么??
视图模型绝对有一个目的,但它们包含的内容应该完全由视图或其消费者的需求决定。通常,这些是实体和相关数据的简化视图或“扁平化”表示。存储库的工作不是为这些视图模型提供服务,它应该只是实体的一个薄包装器,以提供一个简单的抽象点作为单元测试的边界,或者确保执行核心查询规则。
通用存储库的主要问题,无论它们返回实体还是视图模型,都使得支持高效查询变得非常困难和/或复杂。想想你需要做什么来支持:
EF 及其
IQueryable
可以通过 Linq 促进所有这些功能,其中典型的通用存储库模式使支持这些功能成为一项复杂的重新发明轮子的练习,它仍然将 EF 依赖规则“泄漏”到您的代码中(抽象出的常见参数) EF),或者导致没有它们的代码。 (缓慢、占用内存的混乱)