0

Here is the example code of what I'm trying to do, and I'm getting the NullReferenceException. If I remove OneToManyCascadeDeleteConvention then everything works fine. Can anyone please help me understand the problem here.

public class MessageBoard
{
    public int Id { get; set; }
}

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

    public int Id { get; set; }

    [Required]
    public int MessageBoardId { get; set; }

    public virtual MessageBoard MessageBoard { get; set; }

    public virtual ICollection<Message> Messages { get; set; }
    public virtual ICollection<PostHistory> PostHistories { get; set; }
}

public class Message
{
    public int Id { get; set; }

    [Required]
    public int PostId { get; set; }

    public virtual Post Post { get; set; }

    public virtual ICollection<MessageHistory> MessageHistories { get; set; }
}

public class MessageBoardVersion
{
    public int Id { get; set; }

    [Required]
    public int MessageBoardId { get; set; }

    public virtual MessageBoard MessageBoard { get; set; }

    public virtual ICollection<PostHistory> PostHistories { get; set; }
}

public class PostHistory
{
    public PostHistory()
    {
        this.MessageHistories = new HashSet<MessageHistory>();
    }

    [Key, Column(Order = 0)]
    [ForeignKey("MessageBoardVersion")]
    public int MessageBoardVersionId { get; set; }

    [Key, Column(Order = 1)]
    [ForeignKey("Post")]
    public int PostId { get; set; }

    public virtual MessageBoardVersion MessageBoardVersion { get; set; }

    public virtual ICollection<MessageHistory> MessageHistories { get; set; }

    public virtual Post Post { get; set; }
}

public class MessageHistory
{
    [Key, Column(Order = 2)]
    [ForeignKey("Message")]
    public int MessageId { get; set; }

    [Key, Column(Order = 0)]
    [ForeignKey("PostHistory")]
    public int MessageBoardVersionId { get; set; }

    [Key, Column(Order = 1)]
    [ForeignKey("PostHistory")]
    public int PostId { get; set; }

    public virtual PostHistory PostHistory { get; set; }

    public virtual Message Message { get; set; }
}

public class MessageHistoryConfiguration : EntityTypeConfiguration<MessageHistory>
{
    public MessageHistoryConfiguration()
    {
        this.HasRequired(p => p.Message).WithMany(p => p.MessageHistories).WillCascadeOnDelete(false);
        this.HasRequired(p => p.PostHistory).WithMany(p => p.MessageHistories).WillCascadeOnDelete(true);
    }
}

public class PostHistoryConfiguration : EntityTypeConfiguration<PostHistory>
{
    public PostHistoryConfiguration()
    {
        this.HasRequired(p => p.MessageBoardVersion).WithMany(p => p.PostHistories).WillCascadeOnDelete(false);
    }
}

public class Model1Container : DbContext
{
    public Model1Container()
        : base("name=Model1Container")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

        /*
        *  
        * If I do Remove<OneToManyCascadeDeleteConvention> then code works fine
        */
        //modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        //modelBuilder.Configurations.Add(new PostHistoryConfiguration());
        modelBuilder.Configurations.Add(new MessageHistoryConfiguration());
    }

    public DbSet<MessageBoard> MessageBoards { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<Message> Messages { get; set; }
    public DbSet<MessageBoardVersion> MessageBoardVersions { get; set; }
    public DbSet<PostHistory> PostHistories { get; set; }
    public DbSet<MessageHistory> AnswerHistories { get; set; }
}

There is a multiple cascade path error, so If I try to disable cascade on delete then I get the following exception

System.NullReferenceException was unhandled
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=EntityFramework
StackTrace:
at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Configure(EdmEntityType entityType, EdmModel model)
at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.ConfigureEntities(EdmModel model)
at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.Configure(EdmModel model)
at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)
at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.CreateObjectContextForDdlOps()
at System.Data.Entity.Database.Create(Boolean skipExistsCheck)
at System.Data.Entity.Database.Create()
at ConsoleApplication2.Program.Main(String[] args) in c:\Users\dhawalh\Documents\Visual Studio 2012\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 160
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

The only way I can make the code work if by removing OneToManyCascadeDeleteConvention..

 modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

I'm not sure why I'm getting the null reference exception. Can anyone please help? thanks!

4

1 回答 1

0

使用 Fluent API ( ) 定义外键HasForeignKey

public MessageHistoryConfiguration()
{
    this.HasRequired(p => p.Message)
        .WithMany(p => p.MessageHistories)
        .HasForeignKey(p => p.MessageId)
        .WillCascadeOnDelete(false);

    //this.HasRequired(p => p.PostHistory)
    //    .WithMany(p => p.MessageHistories)
    //    .HasForeignKey(p => new { p.MessageBoardVersionId, p.PostId })
    //    .WillCascadeOnDelete(true);
}

第二个映射是多余的(因此我已将其注释掉),因为默认情况下所需的关系将具有级联删除。如果您真的想添加此映射,请包含HasForeignKey如上所示的以将配置与数据注释匹配。

同样在PostHistoryConfiguration

public PostHistoryConfiguration()
{
    this.HasRequired(p => p.MessageBoardVersion)
        .WithMany(p => p.PostHistories)
        .HasForeignKey(p => p.MessageBoardVersionId)
        .WillCascadeOnDelete(false);
}

OnModelCreating

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

    modelBuilder.Configurations.Add(new PostHistoryConfiguration());
    modelBuilder.Configurations.Add(new MessageHistoryConfiguration());
}

对我来说,它毫无例外地起作用。我不知道为什么会发生异常,这可能是 EF 中的错误。但另一方面,您的映射配置有点混乱,尤其是您将数据注释和(不完整)映射与 Fluent API 的混合。我会决定一个或另一个 - 至少每个实体,但最好是整个模型的 Fluent API(因为在任何情况下您都需要 Fluent API 才能禁用级联删除)。

于 2013-08-11T12:49:25.857 回答