【问题标题】:c# Entity Framework select into derived childc#实体框架选择到派生的孩子
【发布时间】:2015-12-03 15:27:01
【问题描述】:

所以我需要选择一个Task() 对象,它是Attachments() 对象,带有Include(),像这样:

var tmp = cntx.Tasks.Include( at => at.Attachments ).FirstOrDefault(t => t.Id == id ); 

它工作正常,MVC api 控制器可以将它序列化为 json,列出所有的 Attachmnet,基本上它工作得很好。

现在我的问题是,我需要在 Task() 中添加 3 个额外的字符串属性(为了更清楚的例子,我只使用下面的 +1 字符串)

 public class TaskView : DataClasses.Task {
    public string BusinessName { get; set; }
}

这些道具不是Task() 的导航属性,实际上它来自其他几个表。现在我可以将之前的查询与表格结合起来,但我不确定如何选择之前完全填充的 Task 对象,所有这些对象都是导航 Attachment() 对象,并将其转换为 TaskView obj,并添加了 BusinessName细绳。

有什么想法吗?

【问题讨论】:

  • BusinessName 来自哪里?它是否来自以任何方式与Task 相关的实体,是否可以从导航属性访问?
  • 不,它不能作为导航属性访问,它来自旧表,但我可以加入()它。如果需要,我可以重写基类,使其成为导航属性,但这需要一段时间,所以如果可能的话,我想要一个“更简单”的答案,比如 select( t => new TaskView { task = task.base() , 企业名 = 表名.prop })。如果可能的话,我不确定,我知道我可以选择 2 个对象到第三个对象中,但不能选择继承的孩子。

标签: c# entity-framework linq inheritance select


【解决方案1】:
public class TaskView : DataClasses.Task {
    public string BusinessName { get; set; }
    // Create constructor for Task
    public TaskView(DataClasses.Task task)
    {
       // Copy properties here
    }
}

那么你可以这样做:

var tmp = cntx.Tasks
  .Include(at => at.Attachments)
  .Where(t => t.Id == id)
  .Select(t=> new TaskView(t) { BusinessName=...})
  .FirstOrDefault();

或者您可以在 TaskView 上创建一个属性,从 TaskView 设置(并可能获取)一个任务,然后在 LINQ 查询中设置它。

或者这样做:

public class TaskView {
    public string BusinessName { get; set; }
    public DataClasses.Task Task { get; set;}
}

然后:

var tmp = cntx.Tasks
  .Include(at => at.Attachments)
  .Where(t => t.Id == id)
  .Select(t=> new TaskView { Task=t,BusinessName=...})
  .FirstOrDefault();

【讨论】:

  • 当然,如果您认为 Task 的属性将来可能会发生变化,您始终可以使用此处的答案之一:stackoverflow.com/questions/930433/… 复制所有属性。
  • 使用 linq CopyProperties 扩展像冠军一样工作。谢谢老哥!
【解决方案2】:

不能将基类实例“强制转换”为派生类实例。您需要创建一个新的TaskView 实例并复制源Task 的所有属性。

如果你负担得起,最好切换到包含而不是像这样的继承

public class TaskView
{
    public Task Task { get; set; }
    public string BusinessName { get; set; }
    // ...
}

【讨论】:

  • 是的,这是个好主意,所以我只选择基本任务对象和附加属性。由于附加的包装器对象,将其序列化为 json 不会那么好,但我可以看到它在完成这项工作!如果我的问题没有答案,我稍后会接受您的解决方法作为答案。
【解决方案3】:

不要将实体与传输层及其视图混淆。如果您像这样为传输层创建另外两个类,则更好的解决方案:

public class TaskDto 
{
  public long Id {get; set;}
  public List<AttachmentsDto> Attachments {get; set;}
}
public class AttachmentsDto 
{
  public long Id {get; set;}
}

还有两个用于没有像以前那样继承的视图。您还需要创建一些帮助类,用于将实体映射到 dto 以及从 dto 映射到视图。

var dtos = cntx.Tasks.Include( at => at.Attachments ).FirstOrDefault(t => t.Id == id ).Select(x => new TaskDto 
{
  Id = x.Id,
  Attachments = x.Attachments.Select(y => new AttachmentsDto { Id = y.Id }).ToList()
});

【讨论】:

    【解决方案4】:

    如果我正确理解您的问题,请尝试使用选择查询。
    比如:

    var tmp = from o in cntx.Tasks.Include( at => at.Attachments ) 
    were (o.id == id) 
    select new TaskView()
    {
     //Properties here
     //e.g
     Id = o.Id,
     Attachments = o.Attachments,
     BusinessName = "YourBusinessName"
    };
    

    【讨论】:

    • 是的,我需要一些非常相似的东西,除非我硬编码了所有的道具,比如 prop1 = o1.prop1,然后如果我更改 Task() 基类,我需要重写所有相关的东西。所以我想要这个输出,但是可以选择像 { this.base() = task, BusinessName = sometable.someprop }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多