【问题标题】:When an entity has more than one 0..1:n relationships to another entity, how to define them using Fluent API?当一个实体与另一个实体有多个 0..1:n 关系时,如何使用 Fluent API 定义它们?
【发布时间】:2015-01-19 22:53:33
【问题描述】:

我正在开发 Azure 移动服务,并且在我的模型中我有一个实体 Message,它在以下声明之后与自身相关:

  • 一个Message可能有一个父Message,一个Message可能是许多Messages的父。

我的班级定义如下:

public partial class Message
{
    public Message()
    {
        this.Messages = new HashSet<Message>();
    }

    public int Id { get; set; }
    public int CreatedById { get; set; }
    public int RecipientId { get; set; }
    public int ParentId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public int MessageTypeId { get; set; }
    public Nullable<MessageType> Type { get; set; }
    public Nullable<bool> Draft { get; set; }
    public Nullable<bool> Read { get; set; }
    public Nullable<bool> Replied { get; set; }
    public Nullable<bool> isDeleted { get; set; }

    [JsonIgnore]
    public virtual User CreatedBy { get; set; }
    [JsonIgnore]
    public virtual User Recipient { get; set; }
    [JsonIgnore]
    public virtual ICollection<Message> Messages { get; set; }
    [JsonIgnore]
    public virtual Message Parent { get; set; }
}

我的 DTO 是这样的:

public class MessageDTO : EntityData 
{
    public string CreatedById { get; set; }
    public string RecipientId { get; set; }
    public string ParentId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public string Type { get; set; }
    public Nullable<bool> Draft { get; set; }
    public Nullable<bool> Read { get; set; }
    public Nullable<bool> Replied { get; set; }
    public Nullable<bool> isDeleted { get; set; }

}

我像这样使用 AutoMapper 映射了这两个类:

        /*
         * Mapping for Message entity
         */
        cfg.CreateMap<Message, MessageDTO>()
            .ForMember(messageDTO => messageDTO.Id, map => map.MapFrom(message => MySqlFuncs.LTRIM(MySqlFuncs.StringConvert(message.Id))))
            .ForMember(messageDTO => messageDTO.ParentId, map => map.MapFrom(message => MySqlFuncs.LTRIM(MySqlFuncs.StringConvert(message.ParentId))))
            .ForMember(messageDTO => messageDTO.CreatedById , map => map.MapFrom(message => MySqlFuncs.LTRIM(MySqlFuncs.StringConvert(message.CreatedById ))))
            .ForMember(messageDTO => messageDTO.RecipientId, map => map.MapFrom(message => MySqlFuncs.LTRIM(MySqlFuncs.StringConvert(message.RecipientId))))
            .ForMember(messageDTO => messageDTO.Type, map => map.MapFrom(message => Enum.GetName(typeof(MessageType), message.MessageTypeId)));

        cfg.CreateMap<MessageDTO, Message>()
            .ForMember(message => message.Id, map => map.MapFrom(messageDTO => MySqlFuncs.LongParse(messageDTO.Id)))
            .ForMember(message => message.ParentId, map => map.MapFrom(messageDTO => MySqlFuncs.LongParse(messageDTO.ParentId)))
            .ForMember(message => message.CreatedById , map => map.MapFrom(messageDTO => MySqlFuncs.LongParse(messageDTO.CreatedById )))
            .ForMember(message => message.RecipientId, map => map.MapFrom(messageDTO => MySqlFuncs.LongParse(messageDTO.RecipientId)));

我的 Fluent API 配置是:

        this.Property(m => m.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        this.HasRequired(m => m.Parent).WithMany(p => p.Messages).WillCascadeOnDelete(true);
        this.HasRequired(m => m.Recipient).WithMany(u => u.MessagesReceived).WillCascadeOnDelete(false);
        this.HasRequired(m => m.CreatedBy).WithMany(u => u.MessagesCreated).WillCascadeOnDelete(false);

但是当我尝试插入新消息时,我收到以下错误:

操作失败,出现以下错误:'Entities in “MobileServiceContext.Messages”参与“Message_CreatedBy” 关系。找到 0 个相关的“Message_CreatedBy_Target”。 1 'Message_CreatedBy_Target' 是预期的。

从这个错误中,我了解到我的 Message 期望有一个 Parent,但由于这将是第一条 Message没有 Parent,也不是每个 Message 都会有一个父母。在我的 Fluent API 配置中,我根据需要定义了 Parent 属性,因为当我将其设置为可选时,在尝试插入 Message 时,我得到了以下错误:

在模型过程中检测到一个或多个验证错误 生成:FollowAppApi.Models.Message_Parent: : 多重性 与 Role 中的引用约束冲突 关系“Message_Parent”中的“Message_Parent_Target”。因为所有 依赖角色中的属性是不可为空的,多重性 Principal Role 必须是 '1'。

我发送到端点的 JSON 如下:

{
  "createdById": "1",
  "recipientId": "2",
  "title": "sample string 4",
  "content": "sample string 5",
  "type": "Alert",
  "draft": true,
  "read": true,
  "replied": true,
  "isDeleted": false
}

如何设置我的配置以在这种情况下或任何其他应存在选项属性的情况下定义可选属性?

编辑 1

所以我检查并read this 在处理一个实体与另一个实体有两个关系的情况时,我添加了 InverseProperty 注释并得到以下错误:

操作失败并出现以下错误:'无法确定 相关操作的有效排序。由于存在依赖关系 外键约束、模型要求或存储生成 价值观。

据我记得,这个错误是指存在一个循环引用,我猜它来自 Parent 属性或者可能是 User 与 Message 的关系,但我不太确定。

这个错误的原因是什么?

【问题讨论】:

    标签: c# entity-framework azure-mobile-services ef-fluent-api


    【解决方案1】:

    所以出现以下错误:

    操作失败并出现以下错误:'无法确定 相关操作的有效排序。由于存在依赖关系 外键约束、模型要求或存储生成 价值观。

    是由于消息中的 Parent 属性不可为空。请注意,这是在 Model 类上,而不是 DTO,因为 string 已经是可为空的类型。

    所以在消息中我不得不改变:

        public int ParentId { get; set; }
    

    为此:

        public Nullable<int> ParentId { get; set; }
    

    这允许我在我的 POST 端点上插入消息。

    【讨论】:

      【解决方案2】:

      当您有自引用对象时,您需要手动提供外键属性。

      this.HasOptional(m => m.Parent) .WithMany(p => p.Messages) .HasForeignKey(m => m.ParentId) .WillCascadeOnDelete(true);

      【讨论】:

      • 我意识到我的错误与我的想法不同,所以我更改了标题以反映这一点
      猜你喜欢
      • 1970-01-01
      • 2016-01-13
      • 2013-10-20
      • 1970-01-01
      • 2014-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-10
      相关资源
      最近更新 更多