Reputation: 18068
I have two classes in console application.
Person
:
class Person {
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public override string ToString() {
return Id + " " + FirstName + " " + LastName;
}
}
and Order
:
class Order {
//Id to domyslna nazwa na identyfikator -> klucz glowny
public int Id { get; set; }
public int Total { get; set; }
public virtual Person Owner { get; set; }
public override string ToString() {
return Id + " " + Total;
}
}
My dbContext
is:
class ApplicationDbContext : DbContext {
public DbSet<Person> Persons { get; set; }
public DbSet<Order> Orders { get; set; }
public ApplicationDbContext()
: base("Olek2") {
Configuration.LazyLoadingEnabled = true;
Configuration.ProxyCreationEnabled = true;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public static ApplicationDbContext Create() {
return new ApplicationDbContext();
}
}
I generated fresh database by update-database
.
In Main
method I try to fetch Person
and then access person's orders but I get null pointer exception on p1.Orders.Count()
. I made properties virtual, also enabled lazy loading, i don't know where the problem is.
static void Main(string[] args) {
ApplicationDbContext context = new ApplicationDbContext();
Person p1 = context.Persons.Find(1);
Console.WriteLine(p1); // THIS WORKS
Console.WriteLine(context.Orders.Count()); //THIS IS 1
Console.WriteLine(p1.Orders.Count()); //EXCEPTION HERE
Console.ReadKey();
}
Also my Seed
method:
protected override void Seed(ApplicationDbContext context) {
Person person = null;
if (!context.Persons.Any()) {
person = new Person() { FirstName = "Alaaaaa", LastName = "Kowlaska" };
context.Persons.AddOrUpdate(person);
}
if (!context.Orders.Any()) {
context.Orders.AddOrUpdate(new Order() { Total = 100, Owner = person });
}
context.SaveChanges();
}
EDIT:
I got a hunch that it has something to do with public static ApplicationDbContext Create()
has 0 references (VS2013 indicates that) in my console application(which fails).
In my ASP.NET-MVC(works fine) it was referenced by:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
....
}
EDIT2 I had a hunch it does not seem to be connected anyhow.
Upvotes: 2
Views: 749
Reputation: 49095
Since your entities are not marked with the public
modifier (which means by default the compiler will make them internal
), EF will not be able to generate proxies for the entity type.
Looking at the source code of EntityProxyFactory
(line 577):
private static bool CanProxyType(EntityType ospaceEntityType)
{
TypeAttributes access = ospaceEntityType.ClrType.Attributes & TypeAttributes.VisibilityMask;
ConstructorInfo ctor = ospaceEntityType.ClrType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, Type.EmptyTypes, null);
bool accessableCtor = ctor != null && (((ctor.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) ||
((ctor.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family) ||
((ctor.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem));
return (!(ospaceEntityType.Abstract ||
ospaceEntityType.ClrType.IsSealed ||
typeof(IEntityWithRelationships).IsAssignableFrom(ospaceEntityType.ClrType) ||
!accessableCtor) &&
access == TypeAttributes.Public);
}
You can clearly notice the last line of CanProxyType
checking whether the entity type is indeed public
.
Now, since you don't initialize Person.Orders
(in the constructor or anywhere else) and no proxy is involved to intercept the call to Orders
(initialize it and detect the association to Order.Person
), you end up with Orders
being null and NRE is thrown.
Upvotes: 2