【问题标题】:Entity Framework Core - retrieve all columns except a few in a generic wayEntity Framework Core - 以通用方式检索除少数列之外的所有列
【发布时间】:2020-03-11 16:05:24
【问题描述】:

我想知道我的问题是否有比这个更好的解决方案 https://entityframeworkcore.com/knowledge-base/44877455/get-all-columns-except-one-in-efcore

我有几个模型有很多列(比如说 20 个),而且很少有列很重 - 斑点。 自然,我希望有一种方法可以轻松地检索数据(它们的列表) - 即排除这几列。 到目前为止,唯一可行的方法是上面链接中提出的方法,即

原型号:

{
    public Rating() { }
    public int IdRating { get; private set; }
    public string IdUser { get; set; }
    public decimal Value { get; private set; }
    public string Comment { get; private set; }
    public bool IsEnabled { get; set; }
    public int IdCorrespondent { get; private set; }}

然后是更轻的版本

public class RatingView
{
    public Rating() { }
    public int IdRating { get; private set; }
    public decimal Value { get; private set; }
}

数据检索是

public List<RatingView> ListRatings()
    {
        return _context.Ratings.Select(x => new RatingView
        {
            IdRating = x.IdRating ,
            Value = x.Value ,
        }).ToList();

    }

第一个问题是这样设置的列太多,其次有几个类似的类,所以解决方案不是很好,并且容易出错,以便将来更改模型。 Automapper 看起来是个不错的方法,但生成的查询并不是最优的——所有的列都被检索了。

谢谢, 阿布斯

【问题讨论】:

  • 视情况而定。但我会考虑将访问较少的列移动到单独的表中,并在真正需要时使用join。比如说,如果使用额外(重)列的轻量查询的 1/100 倍——这可能是一个好方法。否则,您必须使用select 编写手动预测。
  • AM 的设计目的是针对不同的情况使用不同的 DTO。话虽如此,docs.automapper.org/en/latest/….
  • 感谢 Crypt32,在数据库级别拆分表是最好的方法,但不幸的是,它仅在数据库设计阶段可用(在我的情况下继承)。我没有完全理解的第二个建议。您是否建议类似 var All=_context.Ratings.Where(...); var query=All.Select(x => new RatingView { IdRating = x.IdRating , Value = x.Value , }) 所以最后我看不出它与最初的解决方案有何不同?问候,阿布斯
  • 感谢 Lucian,有趣的是,但在 DbSet 上使用 .ProjectTo 似乎会产生最佳查询!我会再做一些测试,但看起来很有希望!

标签: entity-framework ef-core-3.0


【解决方案1】:

查看其他 stackoverflow 帖子并在几个人的帮助下,我找到了 5 个解决方案,其中第一个对我来说是最好的 - 归功于 Lucian Bargaoanu

1) 基于 Automapper

http://docs.automapper.org/en/latest/Queryable-Extensions.html#explicit-expansion
事实上,甚至没有必要创建具有有限数量字段的单独轻量类 - Automapper 可以忽略重字段并且生成的 SQL 查询不会使用它们。

var ratings = _db.Ratings.Where(...).ProjectTo<Rating>(new MapperConfiguration
    (cfg => { cfg.CreateMap<Rating, Rating>()
        .ForMember(d => d.Comment, m => m.Ignore())
        .ForMember(d1 => d1.IdUser, m1 => m1.Ignore()); })).ToList();

如果您想使用像 RatingView 这样的 Light 类 - 只需映射到它而不忽略任何内容。

2) 数据库设计 在设计您的表格时,不要在表格中包含这些沉重的列,而是 - 如果您需要一个模型中的所有内容,请创建一个视图。 不幸的是,如果您要继承该表,则不是一种选择

3) EF Core Table拆分(由Crypt32提出) 可以使用 EF Core 机制进行表拆分

https://docs.microsoft.com/en-us/ef/core/modeling/table-splitting 这里也有解释 EFCore Map 2 entities to same table

我认为 EF 核心版本 3 是可能的,因为我在 Oracle 中使用 EF 核心,所以在撰写本文时它对我不可用。 数据库中不需要视图,不需要映射和列出所有属性,但仍然需要创建这些光照模型类。

4) 初始解决方案同样有效。 https://entityframeworkcore.com/knowledge-base/44877455/get-all-columns-except-one-in-efcore
如前所述,缺点是需要创建许多轻量级并编写具有许多属性的繁琐代码,然后通过您的解决方案的演进来支持所有这些实体。

Kevin Dockx 建议了另外两种可能性,它们都非常好。

5) 视图创建并将光照模型类映射到此处,如下所示:

https://gavilan.blog/2018/07/29/entity-framework-core-2-1-query-types-working-with-views/

缺点是需要支持灯光类和视图 - 与解决方案 3 的问题相同。

6) SQL查询可以使用sql查询的机制,比如

var ratingLIghts= dbContext.Database.SqlQuery<Rating>("select ... from Ratings");

7) Linq 扩展 有一些建议可以使用 SelectExcept 之类的查询来扩展 Linq,如下所示

How to Except Property instead of Select in Lambda LINQ

建议的一段代码不能以最佳方式工作,因为它只是用 NULL 填充要排除的列,但在数据库正在读取所有列时执行的查询 - 不可接受,但我相信以不同方式实现它是可能的

p>

因此,从我的角度来看,最优雅的解决方案是第一个解决方案,代码量最少,并且不太可能出现进一步重构的潜在问题 - 谢谢 Lucian Bargaoanu!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多