的NullReferenceException在EF具有两个导航属性5-6.1.1同一类型 [英] NullReferenceException in EF 5-6.1.1 with two navigation properties to the same type

查看:317
本文介绍了的NullReferenceException在EF具有两个导航属性5-6.1.1同一类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想开始与我对这个问题的解决方法 - 但我花了几个小时今天找出异常的原因,所以我想我会分享

I'd like to start with that I have a workaround for this issue - but I spent a few hours today figuring out the cause of the exception, so I'd thought I'd share

由于两个实体的域:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

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

    public string Name { get; set; }

    public virtual User Owner { get; set; }

    public int? LockedByUserId { get; set; }
    public virtual User LockedByUser { get; set; }

    [Timestamp]
    public byte[] ETag { get; set; }
}



以下配置:

The following configuration:

public class TicketConfiguration : EntityTypeConfiguration<Ticket>
{
    public TicketConfiguration()
    {
        HasRequired(x => x.Owner);

        HasOptional(x => x.LockedByUser)
            .WithMany()
            .HasForeignKey(x => x.LockedByUserId);

        Property(x => x.ETag)
            .IsConcurrencyToken(true);
    }
}

和这个种子:

protected override void Seed(DataContext context)
    {
        var users = context.Set<User>();
        var user = new User
        {
            Name = "Foo"
        };
        users.AddOrUpdate(x => x.Name, user);
        user = users.SingleOrDefault(x => x.Name == "Foo") ?? user;

        var tickets = context.Set<Ticket>();
        tickets.AddOrUpdate(x=>x.Name, new Ticket
        {
            Name = "Bar",
            Owner = user,
        });
    }



我得到一个异常与此:

I get an exception with this:

static void Main()
    {
        var config = new Migrations.Configuration { CommandTimeout = 3600 };
        var migrator = new DbMigrator(config);
        migrator.Update();

        using (var transaction = GetTransaction()) // I've tried with and without transaction
        {
            var context = new DataContext();
            var userId = context.Set<User>().Where(x=>x.Name == "Foo").Select(x=>x.Id).Single();
            var ticket = context.Set<Ticket>().Single(x=>x.Name == "Bar");
            ticket.LockedByUserId = userId;

            context.SaveChanges(); 
            // Exception thrown here 'System.NullReferenceException' 
            //at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.GetOtherEndOfRelationship(IEntityWrapper wrappedEntity)
            //at System.Data.Entity.Core.Objects.EntityEntry.AddRelationshipDetectedByForeignKey(Dictionary`2 relationships, Dictionary`2 principalRelationships, EntityKey relatedKey, EntityEntry relatedEntry, RelatedEnd relatedEndFrom)
            //at System.Data.Entity.Core.Objects.EntityEntry.DetectChangesInForeignKeys()
            //at System.Data.Entity.Core.Objects.ObjectStateManager.DetectChangesInForeignKeys(IList`1 entries)
            //at System.Data.Entity.Core.Objects.ObjectStateManager.DetectChanges()
            //at System.Data.Entity.Core.Objects.ObjectContext.DetectChanges()
            //at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force)
            //at System.Data.Entity.Internal.InternalContext.GetStateEntries(Func`2 predicate)
            //at System.Data.Entity.Internal.InternalContext.GetStateEntries()
            //at System.Data.Entity.Infrastructure.DbChangeTracker.Entries()
            //at System.Data.Entity.DbContext.GetValidationErrors()
            //at System.Data.Entity.Internal.InternalContext.SaveChanges()
            //at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
            //at System.Data.Entity.DbContext.SaveChanges()
            //at EntityFrameworkFkNull.Program.Main(String[] args) in h:\Projects\Spikes\EntityFrameworkFkNull\EntityFrameworkFkNull\Program.cs:line 27
            //at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
            //at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
            //at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
            //at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
            //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()
            transaction.Complete();
        }
    }



获得完整的解决方案,在这里试试自己:<一HREF =https://github.com/mvidacovich/EntityFrameworkFkNull相对=nofollow> https://github.com/mvidacovich/EntityFrameworkFkNull

我相信这是因为门票有两种不同的外键的用户,但被明确配置只是其中之一。

I believe this is because Ticket has two different foreign keys to User but only one of them is explicitly configured.

这会影响EF 5 EF 6至于我。已经测试过自己

This affects EF 5 to Ef 6 as far as I've tested myself.

所以,这引出了一个问题:难道预计EF抛出异常呢?

So, that begs the question: Is it expected that EF throws an exception there?

推荐答案

解决方法是对票务的OWNERID属性。 (见修复分公司在github上解)

The workaround is to have an "OwnerId" property on Ticket. (See fix branch in the solution in github)

所以,票务变为:

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

    public string Name { get; set; }

    public int? OwnerId { get; set; }
    public virtual User Owner { get; set; }

    public int? LockedByUserId { get; set; }
    public virtual User LockedByUser { get; set; }

    [Timestamp]
    public byte[] ETag { get; set; }
}

和票务的配置更改为:

public class TicketConfiguration : EntityTypeConfiguration<Ticket>
{
    public TicketConfiguration()
    {
        HasRequired(x => x.Owner)
            .WithMany()
            .HasForeignKey(x=>x.OwnerId);

        Property(x => x.OwnerId)
            .HasColumnName("Owner_Id");

        HasOptional(x => x.LockedByUser)
            .WithMany()
            .HasForeignKey(x => x.LockedByUserId);

        Property(x => x.ETag)
            .IsConcurrencyToken(true);
    }
}

现在注意明确OWNERID。
为全(固定的)解决方案,请参阅本: https://github.com/mvidacovich / EntityFrameworkFkNull /树/修复

Notice the explicit OwnerId now. See this for the full (fixed) solution: https://github.com/mvidacovich/EntityFrameworkFkNull/tree/Fix

这篇关于的NullReferenceException在EF具有两个导航属性5-6.1.1同一类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆