C# 实体框架4.3访问抽象类集合引发ArgumentNull异常

C# 实体框架4.3访问抽象类集合引发ArgumentNull异常,c#,entity-framework,C#,Entity Framework,我首先使用EntityFramework4.3代码来持久化域模型。域模型由抽象类和具体类组成。我看到实体框架返回的具体类首次尝试访问基类中的对象集合时引发ArgumentNullException 例如,域模型由抽象类组成 public abstract class Foo { public int Id { get; set; } public string Name { get; set; } public virtual ICollection<Attibut

我首先使用EntityFramework4.3代码来持久化域模型。域模型由抽象类和具体类组成。我看到实体框架返回的具体类首次尝试访问基类中的对象集合时引发ArgumentNullException

例如,域模型由抽象类组成

public abstract class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Attibute> attributes { get; set; }

    public string DoSomething()
    {
        return "I'm all fooey";
    }
}

public abstract class Attibute
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Foo> Foos { get; set; }
}
公共抽象类Foo
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection属性{get;set;}
公共字符串DoSomething()
{
返回“我是美食家”;
}
}
公共抽象类Attibute
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection Foos{get;set;}
}
然后我有派生类,比如

public class BadFoo : Foo
{
    public List<BadAttribute> BadAttribs()
    {
        return base.attributes.OfType<BadAttribute>().ToList<BadAttribute>();
    }

    public void BeBad()
    {
        foreach (var a in BadAttribs())
            Console.WriteLine(Name + ": Being bad => " + a.DoingBad());
    }
}

public class GoodFoo : Foo
{
    public List<GoodAttribute> GoodAttribs()
    {
        return base.attributes.OfType<GoodAttribute>().ToList<GoodAttribute>();
    }

    public void BeGood()
    {
       foreach (var a in GoodAttribs())
            Console.WriteLine(Name + ": Being good => " + a.DoingGood());
    }
}


public class BadAttribute : Attibute
{
    public string DoingBad()
    {
        return Name + " : Start being bad";
    }
}

public class GoodAttribute : Attibute
{
    public string DoingGood()
    {
        return Name + " : Start being Good";
    }
}

public class AppearenceAttribute : Attibute
{
    public string Doing()
    {
        return Name + " : defining ones appearance";
    }
}
公共类BadFoo:Foo
{
公共列表BadAttribs()
{
返回base.attributes.OfType().ToList();
}
公共空间
{
foreach(BadAttribs()中的变量a)
Console.WriteLine(Name+”:Being bad=>“+a.DoingBad());
}
}
公共类GoodFoo:Foo
{
公共列表GoodAttribs()
{
返回base.attributes.OfType().ToList();
}
公共空间
{
foreach(GoodAttribs()中的变量a)
Console.WriteLine(Name+”:Being good=>“+a.DoingGood());
}
}
公共类属性:Attibute
{
公共字符串DoingBad()
{
返回名称+“:开始坏”;
}
}
公共类GoodAttribute:Attibute
{
公共字符串DoingGood()
{
返回名称+“:开始良好”;
}
}
公共类外观属性:Attibute
{
公共字符串Doing()
{
返回名称+“:定义外观”;
}
}
然后,我设置数据库上下文,如下所示:

public class EFDbContext : DbContext
{
    public DbSet<Foo> Foos { get; set; }
    public DbSet<Attibute> Attributes { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    }
}

public class EFDbContextInitializer : DropCreateDatabaseAlways<EFDbContext> 
{
    protected override void Seed(EFDbContext context)
    {
        List<Attibute> attribs = new List<Attibute>
            {
                new BadAttribute { Name = "Gluttony" },
                new BadAttribute { Name = "Greed" },
                new GoodAttribute { Name = "Honesty" },
                new GoodAttribute { Name = "Humility" },
                new AppearenceAttribute { Name = "Colour" }
            };
        attribs.ForEach(a => context.Attributes.Add(a));
        context.SaveChanges();

        BadFoo badOne = new BadFoo { Name = "badOne", attributes = new List<Attibute>)};

        context.Attributes.OfType<BadAttribute>().ToList().ForEach(a => badOne.attributes.Add(a));
        context.Attributes.OfType<AppearenceAttribute>().ToList().ForEach(a => badOne.attributes.Add(a));

        context.Foos.Add(badOne);
        context.SaveChanges();

        GoodFoo goodOne = new GoodFoo { Name = "GoodOne", attributes = new List<Attibute>() };

        context.Attributes.OfType<GoodAttribute>().ToList().ForEach(a => goodOne.attributes.Add(a));
        context.Attributes.OfType<AppearenceAttribute>().ToList().ForEach(a => goodOne.attributes.Add(a));

        context.Foos.Add(goodOne);
        context.SaveChanges();

        base.Seed(context);
    }
}
       Database.SetInitializer<EFDbContext>(new EFDbContextInitializer());

        EFDbContext context = new EFDbContext();

        var foos = context.Foos.OfType<BadFoo>().ToList();
        foreach (var f in foos)
            f.BeBad();

        var foos2 = context.Foos.OfType<GoodFoo>().ToList();
        foreach (var f in foos2)
            f.BeGood();

        Console.ReadKey();
公共类EFDbContext:DbContext
{
公共DbSet Foos{get;set;}
公共数据库集属性{get;set;}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
基于模型创建(modelBuilder);
}
}
公共类EFDbContextInitializer:DropCreateDatabaseAlways
{
受保护的重写无效种子(EFDbContext上下文)
{
List attribs=新列表
{
新属性{Name=“Gluttony”},
新属性{Name=“Greed”},
新的GoodAttribute{Name=“诚实”},
新的GoodAttribute{Name=“humbility”},
新外观属性{Name=“color”}
};
attribs.ForEach(a=>context.Attributes.Add(a));
SaveChanges();
BadFoo badOne=newbadfoo{Name=“badOne”,attributes=newlist)};
ForEach(a=>badOne.Attributes.Add(a));
ForEach(a=>badOne.Attributes.Add(a));
context.Foos.Add(badOne);
SaveChanges();
GoodFoo goodOne=newgoodfoo{Name=“goodOne”,attributes=newlist()};
ForEach(a=>goodOne.Attributes.Add(a));
ForEach(a=>goodOne.Attributes.Add(a));
context.Foos.Add(goodOne);
SaveChanges();
种子(上下文);
}
}
然后,我使用我的模型,如下所示:

public class EFDbContext : DbContext
{
    public DbSet<Foo> Foos { get; set; }
    public DbSet<Attibute> Attributes { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    }
}

public class EFDbContextInitializer : DropCreateDatabaseAlways<EFDbContext> 
{
    protected override void Seed(EFDbContext context)
    {
        List<Attibute> attribs = new List<Attibute>
            {
                new BadAttribute { Name = "Gluttony" },
                new BadAttribute { Name = "Greed" },
                new GoodAttribute { Name = "Honesty" },
                new GoodAttribute { Name = "Humility" },
                new AppearenceAttribute { Name = "Colour" }
            };
        attribs.ForEach(a => context.Attributes.Add(a));
        context.SaveChanges();

        BadFoo badOne = new BadFoo { Name = "badOne", attributes = new List<Attibute>)};

        context.Attributes.OfType<BadAttribute>().ToList().ForEach(a => badOne.attributes.Add(a));
        context.Attributes.OfType<AppearenceAttribute>().ToList().ForEach(a => badOne.attributes.Add(a));

        context.Foos.Add(badOne);
        context.SaveChanges();

        GoodFoo goodOne = new GoodFoo { Name = "GoodOne", attributes = new List<Attibute>() };

        context.Attributes.OfType<GoodAttribute>().ToList().ForEach(a => goodOne.attributes.Add(a));
        context.Attributes.OfType<AppearenceAttribute>().ToList().ForEach(a => goodOne.attributes.Add(a));

        context.Foos.Add(goodOne);
        context.SaveChanges();

        base.Seed(context);
    }
}
       Database.SetInitializer<EFDbContext>(new EFDbContextInitializer());

        EFDbContext context = new EFDbContext();

        var foos = context.Foos.OfType<BadFoo>().ToList();
        foreach (var f in foos)
            f.BeBad();

        var foos2 = context.Foos.OfType<GoodFoo>().ToList();
        foreach (var f in foos2)
            f.BeGood();

        Console.ReadKey();
Database.SetInitializer(新的EFDbContextInitializer());
EFDbContext=新的EFDbContext();
var foos=context.foos.OfType().ToList();
foreach(foos中的var f)
f、 贝巴德();
var foos2=context.Foos.OfType().ToList();
foreach(foos2中的变量f)
f、 贝古德();
Console.ReadKey();
当从Foo派生的具体类首次尝试使用Foo基类中的集合时,会引发异常。在本例中,BadFoo实例第一次调用BeBad()方法

我不确定这是因为EF懒散地加载集合、C#处理抽象/具体类的方式还是域模型吸引了任何人来解释/启发我这个问题

如果我将派生属性类BadFoo和GoodFoo中访问基属性的方式替换为返回基类集合属性的类型筛选列表的属性,请注意:

public class GoodFoo : Foo
{
    public List<GoodAttribute> GoodAttribs()
    {
        return base.attributes.OfType<GoodAttribute>().ToList<GoodAttribute>();
    }
}
公共类GoodFoo:Foo
{
公共列表GoodAttribs()
{
返回base.attributes.OfType().ToList();
}
}

EF向表中添加一个_Id列,这是为什么

EF代码首先基于配置和上下文定义构建db模型元数据。您已经将EF设置为使用抽象Foo和属性类作为实体。所以它试图使用它

public class EFDbContext : DbContext
{
    public DbSet<Foo> Foos { get; set; }
    public DbSet<Attibute> Attributes { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    }
}
公共类EFDbContext:DbContext
{
公共DbSet Foos{get;set;}
公共数据库集属性{get;set;}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
基于模型创建(modelBuilder);
}
}
它不知道关于您的子代和类的任何信息,也不知道如何映射它们。在我看来,您不能使用抽象类作为实体,因为它没有任何意义


在任何情况下,Foo和Attibute类本质上都不是抽象类。他们没有任何抽象的方法。我建议您阅读更多关于C#或abstract关键字中的抽象类的内容。

是否将
base.attributes
替换为
this.attributes
修复了任何问题?否不会修复任何问题。如果禁用EF代理创建,从导航属性中删除virtual,然后将派生类型上的属性(例如GoodFoo.GoodAttribs)替换为访问基类属性的类方法,那么我可以让它工作。不确定派生类型上的属性访问器为何无法工作。存在相同问题:(