【问题标题】:Navigation property null with Entity Framework带有实体框架的导航属性 null
【发布时间】:2017-03-27 12:03:46
【问题描述】:

我首先使用实体​​框架和代码。我的关系属性不断中断。

我有对象Element

public class Element : IElement
{
    // ... some event handlers (removed)

    [Key]
    public Guid ID { get; set; } = Guid.NewGuid();

    public string Name { get; set; }

    // navigation properties
    public virtual ElementType ElementType { get; private set; }

    public virtual NotifiableCollection<Property> Properties { get; private set; } = new NotifiableCollection<Property>();

    // Parameterless constructor for serialization
    private Element() { }

    public Element(ElementType elementType) : base()
    {
        // loop through and create Properties for each Property Type
        ElementType = elementType;
        if (ElementType?.PropertyTypes != null)
        {
            ElementType.PropertyTypes.ToList().ForEach((property) =>
            {
                Properties.Add(new Property(property));
            });
        }
    }
}

还有ElementType:

public class ElementType : IElementType
{
    // ... some event handlers (removed)

    [Key]
    public Guid ID { get; set; } = Guid.NewGuid();

    public string Name { get; set; }

    // navigation properties
    public virtual NotifiableCollection<PropertyType> PropertyTypes { get; set; } = new NotifiableCollection<PropertyType>();

    public virtual NotifiableCollection<Element> Elements { get; set; } = new NotifiableCollection<Element>();

    public ElementType()
    {
        // ensure our Element's get updates
        PropertyTypes.CollectionChanged += (e, a) =>
        {
            //update the database to send out renewal to interested entities
            if (a.ChangeType == ChangeType.Added)
            {
                foreach (Element element in Elements)
                {
                    element.Properties.Add(new Property(a.Item));
                }
            }
        };
    }
}

当我第一次创建这些对象时它工作正常(因为我已明确设置导航属性然后保存):

但是,当我关闭所有内容并从数据库中获取这些内容时:

导航属性未解析。表定义很好地设置了外键关系:

CREATE TABLE [dbo].[Elements] (
    [ID]             UNIQUEIDENTIFIER NOT NULL,
    [Name]           NVARCHAR (MAX)   NULL,
    [ElementType_ID] UNIQUEIDENTIFIER NULL,
    CONSTRAINT [PK_dbo.Elements] PRIMARY KEY CLUSTERED ([ID] ASC),
    CONSTRAINT [FK_dbo.Elements_dbo.ElementTypes_ElementType_ID] FOREIGN KEY ([ElementType_ID]) REFERENCES [dbo].[ElementTypes] ([ID])
);


GO
CREATE NONCLUSTERED INDEX [IX_ElementType_ID]
    ON [dbo].[Elements]([ElementType_ID] ASC);

我可以看到数据都是正确的:

ID                                    Name                             ElementType_ID
ff186746-62cb-4246-9c64-f2d007b23ac0  Aircon Test 27/03/2017 12:54:03  57d93ac1-ad3b-4718-a593-80639cc24907

与 ElementType 表中的 ID 匹配。

我的存储库中有这个设置:

context.Configuration.ProxyCreationEnabled = true;
context.Configuration.LazyLoadingEnabled = true;

在我尝试解析此属性时,上下文仍然处于活动状态。

一切正常,但我在使用 EF 时多次遇到此问题,我的导航属性只是随机中断。我不记得接触过与此元素相关的任何代码,只是运行它,现在它不起作用。有人可以帮忙吗?

编辑:这是存储库代码:

public sealed class Repository : IRepository
{
    public event ObjectMaterializedEventHandler ObjectMaterialized;

    public Repository() {
        (context as IObjectContextAdapter).ObjectContext.ObjectMaterialized += ObjectContext_ObjectMaterialized; ;
        context.Configuration.ProxyCreationEnabled = true;
        context.Configuration.LazyLoadingEnabled = true;
    }

    // I do this to wire in some events later
    private void ObjectContext_ObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
    {
        ObjectMaterialized?.Invoke(this, e);
    }

    private DataContext context = new DataContext(false);

    public IEnumerable<T> GetAll<T>() where T : class
    {
        return context.Set<T>().ToList() as IEnumerable<T>;
    }

    public T GetItem<T>(Guid id) where T : class
    {
        return context.Set<T>().Find(id) as T;
    }
    ...
}

上下文这样存储它们:

public class DataContext : DbContext
{
    ...
    public DbSet<Element> Elements { get; set; }
    public DbSet<ElementType> ElementTypes { get; set; }
}

我认为这与访问有关。我正在使用 context.Set().Find(id) 作为 T 访问元素,但它失败了。但是,如果我浏览 ElementTypes,找到它的实体列表,那么它工作正常。

【问题讨论】:

  • 您是否将 EF 上下文重用于多个操作(即:您是否将其保存在某个静态\实例变量中)?
  • 您能否展示一下如何从数据库中获取实体?您是否将上下文/存储库包装在 using 块中?
  • 是的,上下文保留在存储库中。我将从这里添加一些代码来显示检索。
  • 在尝试枚举导航属性之前存储库是否已销毁?
  • ` as T` 无法更改实际类型。看起来 Find 没有返回代理。因此,要么 (A) 出于某种原因 Element 不符合延迟加载到 EF 的条件,要么 (B) 您手动添加了 Element 实例。如果你下断点并尝试context.Set&lt;Element&gt;().Create();,它是否返回代理(消除大小写(B))?

标签: c# entity-framework


【解决方案1】:

在 Ivan 的帮助下在 cmets 中找到了答案。

问题在于有一个私有构造函数:

// Parameterless constructor for serialization
private Element() { }

proxies 的要求之一是公共或受保护的构造函数:

对于要创建的这些代理中的任何一个:自定义数据类必须是 声明为可公开访问。

  • 不得密封自定义数据类(Visual 中的 NotInheritable 基本)

  • 自定义数据类不能是抽象的(Visual 中的 MustInherit 基本)。

  • 自定义数据类必须有一个公共或受保护的构造函数 没有参数。使用受保护的构造函数 如果您希望使用 CreateObject 方法创建一个 POCO 实体的代理。调用 CreateObject 方法不会 保证代理的创建:POCO 类必须遵循 本主题中描述的其他要求。

  • 该类无法实现 IEntityWithChangeTracker 或 IEntityWithRelationships 接口,因为代理类 实现这些接口。

  • ProxyCreationEnabled 选项必须设置为 true。

对于延迟加载代理:每个导航属性必须声明为 公共、虚拟(在 Visual Basic 中可重写)和非密封 (在 Visual Basic 中为 NotOverridable)获取访问器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-21
    • 2016-03-29
    相关资源
    最近更新 更多