从实体框架表中选择特定列

SᴇM*_*SᴇM -2 c# entity-framework

我有一个关于使用实体框架从表中选择特定列的问题。问题是,我正在使用Find()方法通过主键获取所需的表,然后从中获取一些数据。

我有一个包含大量列的表,如果我调用Find()method,它将返回该行的所有列,但是我只想使用例如来自2列的数据。

MyTable table = context.MyTable.Find(id); //Get MyTable object from context, id = primary key
string p1 = table.Prop1;
string p2 = table.Prop2;
Run Code Online (Sandbox Code Playgroud)

这将返回具有所有属性的单个对象(例如,它具有Prop1,Prop2,...,PropN)属性(如果已填充数据库)。所以我知道我可以使用匿名对象或数据传输对象(DTO),但是[question1]是否有其他(但很简单)的方法来获取特定的列?[question2]如果使用Find()(或应该使用Where()/Select())会影响性能吗?

thi*_*hat 6

    var items = context.MyTable.Where(x => x.Id == id)
                  .Select(x => new
                               {
                                    P1 = table.Prop1,
                                    P2 = table.Prop2
                               });
Run Code Online (Sandbox Code Playgroud)

这将转换为sql调用,例如:

SELECT p.Prop1, p.Prop2 FROM mytable p WHERE p.Id = id
Run Code Online (Sandbox Code Playgroud)

  • OP已经承认匿名类型的选项:_“因此,我知道我可以使用匿名对象或数据传输对象(DTO),但是[question1]是否有其他(但很简单)的方法来获取特定列?” _您的答案也有质量问题,简单的代码块是不够的。 (3认同)

SDM*_*SDM 6

另一种选择是将类投影回其自身,并仅提供所需的列。

var table = context.MyTable.Where(mt => mt.Id == id)
                           .Select(mt => new MyTable
                            {
                                Prop1 = mt.Prop1,
                                Prop2 = mt.Prop2
                            })
                           .FirstOrDefault();

string p1 = table.Prop1;
string p2 = table.Prop2;
Run Code Online (Sandbox Code Playgroud)

实际上,您无需创建/维护另一个类即可获得 DTO 的强类型。所有指定的列都将使用该列类型的默认值进行填充。

它在 SQL 中转换为以下内容:

SELECT TOP(1) m.Prop1, m.Prop2 FROM MyTable m WHERE m.Id = @id
Run Code Online (Sandbox Code Playgroud)

Find()与假设您没有指定所有列相比,这确实可以提高性能。

编辑:正如 Gert 提到的,请谨慎使用,因为传递“部分实体”时并不总是显而易见。

  • 如果使用“部分实体”,往往会导致各种意想不到的问题。其一,它是代码中经常出现歧义的根源。现在所有代码都必须知道它接收到的实体类型。 (2认同)

Liq*_*ore 5

使用数据传输对象: DTO,这是一种推荐的微软模式。

简单来说,它们只是保存数据的对象。

然后像有人建议的那样做:

public class MyDto
{
  public string Prop1 {get;set;} = String.Empty
  public string Prop2 {get;set;} = String.Empty
}
MyDto x = new MyDto();
 x = context.MyTable.Where(x => x.Id == id)
                  .Select(x => new MyDto
                               {
                                    P1 = table.Prop1
//I don't want prop 2, for example
                               });
Run Code Online (Sandbox Code Playgroud)

并绕过对象。设置自动属性(C# 6及更高版本)的默认值并仅初始化您想要的属性。

编辑:我读过你不想使用匿名和 DTO,那么你想怎么做。您可以使用对象或匿名。

其他方法只是构建一个分层结构并在需要的地方直接调用查询方法。模式存在是有原因的。

您可以调用针对动态对象的查询。有了这些,您可以分配将在运行时解析的字段,代价是失去强类型。

您可能还想检查使用动态是否具有性能价值。

  • 阅读 OP 所问的内容:所以我知道我可以使用匿名对象或数据传输对象 (DTO),但是还有其他(但简单的)方法来获取特定列吗? (2认同)
  • 实际上,您不能在 EF 投影中使用“动态”类型。EF 是基于静态类型的系统。 (2认同)