【问题标题】:EF Code First, create new object in collection with a proxyEF 代码首先,使用代理在集合中创建新对象
【发布时间】:2011-08-20 03:42:26
【问题描述】:

如何仅使用导航属性集合创建 + 持久化 + 拥有代理到代码优先 poco 的新实例?在下面的代码中,如果使用成员函数创建 POCO,然后再创建 POCO,我将展示您可能希望如何执行此操作。您没有 DbContext,但如果您创建一个对象并使用 DbSet.Add 将其持久化,则返回的对象不是代理,因此您不能反过来使用其 DbSet.Add 添加不同的子对象.

在此代码中,如果您调用 MailingList.AddIncomingMessage("my message"),则会在“OOPS”注释处收到异常,因为创建的 msg 不是代理,因此其 Message.doodads 属性为空。

class Doodad {
  public int ID { get; set; }
  public string doodad { get; set; };
}

class Message {
  public int ID { get; set; }
  public virtual MailingList mailingList { get; set; } 
  public virtual ICollection<Doodad> doodads { get; set; }
  public string text { get; set; }

  public void GetDoodadCreateIfNeeded(string doodad) {
    try {
      // won't be found since we just created this Message
      return this.doodads.First(d => d.doodad == doodad);
    } catch (Exception e) {
      Doodad newDoodad = new Doodad() { doodad=doodad };

      // OOPS! this.doodads == null, because its not a proxy object
      this.doodads.Add(newDoodad);
      return newDoodad;
    }
  }
}

class MailingList {
  public int ID { get; set; }
  public virtual ICollection<Message> messages { get; set; }

  public void AddIncomingMessage(string message) {
    var msg = new Message() { text=message };

    // we have no Context, because we're in a POCO's member function
    this.messages.Add(msg);

    var doodad = msg.GetDoodadCreateIfNeeded("bongo drums");
  }
}

编辑:对不起,我忘了在这个简化的案例中输入属性访问器和 ID,但我在实际代码中使用它们。

【问题讨论】:

标签: entity-framework-4.1 ef-code-first


【解决方案1】:

它与代理无关。它和任何其他代码一样——如果你想使用对象/集合,你必须先初始化它!你的第一个命令:

return this.doodads.First(d => d.doodad == doodad);

不会抛出异常,因为它没有找到doodad,而是因为doodads 为空。

你需要做什么?您需要在首次使用之前初始化集合。你可以做到:

  • 直接在他们的定义中
  • 在实体的构造函数中
  • 在第一次需要它们时在属性 getter(延迟初始化)中 - 这需要将您的字段更改为顺便说一句的属性。在 .NET 中编写类的正确方法
  • 在您的自定义方法中,您可以检查它们是否为空并初始化它们

【讨论】:

  • 我一直担心添加构造函数,因为我不想覆盖数据库中的数据......例如如果我有: public Message() { this.doodads = new IList(); },当已经有装饰物的关联时,这是否会意外覆盖从数据库加载的数据,还是只会在加载数据之前调用(或仅在我明确执行新操作时调用)?
  • 当我使用上述构造函数显式初始化小工具时,当我稍后尝试 context.SaveChanges() 时,我得到: InvalidOperationException “集合已修改;枚举操作可能无法执行。”。我想也许我确实需要代理?
  • Ladislav,你能举一个初始化集合的例子吗?我目前正在创建一个新的 List,并在这样做时出现错误。我应该使用与 List 不同的类型吗?
  • InvalidOperationException "集合已修改;枚举操作可能无法执行。"
  • 将相关代码放入您的问题中。简单的初始化不应该产生这个错误。
【解决方案2】:

作为导航属性的补充,您需要有一个属性是外键的 Id。

所以你的 MailingList 需要有这个属性:

  [Key] // this attribute is important
  public int Id { get; set; }

您必须更改 Message 类以具有以下属性:

public virtual int mailingListId { get; set; 
public virtual MailingList mailingList { get; set; }

{ get; set; } 属性很重要,因此它是一个属性,而不仅仅是一个公共属性。

【讨论】:

  • 很好,Doug,当我制作简化示例以更清楚地解释我的问题时,我忘了包括这些。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-18
  • 2012-01-10
  • 1970-01-01
相关资源
最近更新 更多