【问题标题】:Entity Framework 4.3 accessing abstract Class collection throws ArgumentNull ExceptionEntity Framework 4.3 访问抽象类集合抛出 ArgumentNull 异常
【发布时间】:2012-07-09 15:17:42
【问题描述】:

我首先使用实体​​框架 4.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; }
}

然后我就有了类似的派生类

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";
    }
}

然后我按如下方式设置我的数据库上下文:

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();

当派生自 Foo 的具体类首次尝试使用 Foo 基类中的集合时,将引发异常。在这种情况下,BadFoo 实例第一次调用 BeBad() 方法。

我不确定是不是因为 EF 延迟加载集合,C# 处理抽象/具体类或域模型的方式只是让任何人愿意解释/启发我解决问题?

附带说明,如果我将派生属性类 BadFoo 和 GoodFoo 中访问基属性的方式替换为返回基类集合属性的类型过滤列表的属性,例如:

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

EF 在表中添加了一个 _Id 列,这是为什么呢?

【问题讨论】:

  • this.attributes 替换base.attributes 能解决什么问题吗?
  • No 不能解决任何问题。如果禁用 EF 代理创建,请从导航属性中删除 virtual,然后将派生类型上的属性(例如 GoodFoo.GoodAttribs)替换为访问基类属性的类方法,然后我可以让它工作。不知道为什么派生类型的属性访问器不起作用。
  • 遇到同样的问题 :(

标签: c# entity-framework


【解决方案1】:

EF 代码首先根据配置和上下文定义构建数据库模型元数据。您已将 EF 设置为使用抽象 Foo 和 Attribute 类作为实体。所以它会尝试使用它。

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);
    }
}

它对你的后代类一无所知,也不知道如何映射它们。在我看来,您不能将抽象类用作实体,因为它没有任何意义。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-07
    • 1970-01-01
    • 1970-01-01
    • 2015-10-22
    • 2012-12-08
    相关资源
    最近更新 更多