What is the purpose of virtual in Entity Framework? - c#

I am a beginner to Entity Framework. I have got some terms which are creating problems. I am considering code-first schema
1-to-1 is resolved by by making a property of the child class in parent class and in child class we marks the id of parent class as foreign key.
Like
public class Parent{
//code
public Child Child{get; set;}
}
public class Child{
[ForeignKey("Parent")]
public int ParentId{get; set;}
}
A 1-to-many relation we use
public class Parent {
//code
public IList<Child> Child { get; set; }
}
public class Child {
[ForeignKey("Parent")]
public int ParentId{get; set;}
}
Is this the correct approach?
\*-\* is resolved by adding IList<class> in both classes.
But I was solving a problem where I have 2 classes Categories and Products.
In Product class a property is defined as
public class Products {
public virtual Category Category { get; set; }
}
And in the Category class, products are called in this way
public class Categories {
public virtual ICollection<Product> Products { get; set; }
}
I am confused what is the purpose of virtual Category in product?
Anyone answer please to resolve my confusion

As others have pointed out in the comments, EF uses the virtual keyword to enable lazy loading. The way it does this is by using what is known as a dynamic proxy.
If you are debugging you might notice that the type of your entity is not what you think it is:
Proxy types have names that look something like this:
System.Data.Entity.DynamicProxies
.Blog_5E43C6C196972BF0754973E48C9C941092D86818CD94005E9A759B70BF6E48E6
Entity Framework sees your Entity has the virtual keyword, and will create a dynamic proxy by inheriting from your class and overriding the properties that are marked virtual to enable lazy-loading for those properties.
As mentioned in the msdn I linked to, you will not get a dynamic proxy when you create an instance of your entity using the new keyword (and therefore will not get lazy loading):
var blog1 = new Blog(); // not a dynamic proxy
var blog2 = db.Blogs.Create(); // this is a dynamic proxy
var blog3 = db.Blogs.Find(1); // this is a dynamic proxy

Related

Why navigation property doesn't populate when its class is private?

I have this simple model:
class Parent
{
public int Id { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public virtual Parent Parent { get; set; }
}
class MyContext : DbContext
{
public DbSet<Parent> Parents { get; set; }
public DbSet<Child> Children { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Child>().HasRequired(s => s.Parent).WithMany(s => s.Children).HasForeignKey(s => s.ParentId);
base.OnModelCreating(modelBuilder);
}
}
And when I use MyContext as below, I get null reference exception because child.Parent is null
var context = new MyContext();
var child = context.Children.First();
var parentId = child.Parent.Id; // Parent == null
To solve this problem I have to change the access modifier of Parent and Child classes to be public.
Why is that required ? Or is this just a bug ?
That is not a bug, you are using a feature of Entity Framework called Lazy Loading, and to use it you need to meet some requirements that you can find in this link. One of those requirements is that your entity classes must be public. In that link you will find a proper explanation of why you should meet those requirements, but in summary your issue is because EF can't create a proxy class from your entity, due to that you can't use lazy loading. You already are meeting the main requirement for lazy loading which is your navigation properties must be virtual, but first you must meet the requirements that EF needs to create a proxy class.
As an additional resource I suggest you look this msdn page where you can find all the ways to load related entities using EF.
First, to clear something up: your classes aren't private, they're internal. You can't declare a top-level type (a non-nested type) to be private (see MSDN Access Modifiers for more info).
Second, Lazy Loading is enabled by default for code first. As octaviocci mentioned, if you're expecting to use Lazy Loading you need to declare them public: it's just part of the requirements. By declaring your Navigation properties as virtual you're telling EF that you expect to use lazy loading. If you don't want to, you can (should) remove the virtual keyword. Then, when getting your entities, use the Include method to eagerly load related entities.
var context = new MyContext();
var child = context.Children.Include(c => c.Parent).First();
var parentId = child.Parent.Id;

Controlling TPT-mapping of properties in Entity Framework

I am trying to control how Entity Framework 6 maps my class hierarchy into tables so that the properties in an abstract class in the middle of my hierarchy is mapped to the descendant types, not to its base class.
My class hierarchy is quite simple:
public abstract class BaseType
{
public int Id { get; set; }
public DateTime DateField { get; set; }
}
public abstract class DerivedAbstract : BaseType
{
public string MapToChild { get; set; }
}
public class Concrete1 : DerivedAbstract
{
public int Age { get; set; }
}
public class Concrete2 : DerivedAbstract
{
public string Name { get; set; }
}
I have setup a simple table-per-type hierarchy:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<BaseType>();
modelBuilder.Entity<Concrete1>().ToTable("Concrete1");
modelBuilder.Entity<Concrete2>().ToTable("Concrete2");
}
And this gives me three tables: BaseTypes, Concrete1 and Concrete2. So far I am very happy, but my challenge is that the field MapToChild defined in the DerivedAbstract class is mapped down to the BaseTypes table instead of to both of the Concrete1 and Concrete2 tables.
This makes sense in most cases, but not in the project I am working on. So I am looking for a way to tell Entity Framework that I want the property to be mapped to the two tables Concrete1 and Concrete2 instead.
So far I have been unable to find a way to do this. Does Entity Framework even support it?
This is happening because you are telling it to map BaseType. So it is creating base type as a TPH mapping and adding a discriminator.
If you remove the BaseType mapping you will get a Table for concrete1 and a table for concrete2 which I think it was you want. Right?
Ah... sorry, probably what you want. I can't map your classes so that BaseType is a table and have the MapToChild be in each concrete type. I assume you are doing this so you can query BaseType and get back multiple child types.
So, never mind.

How would you setup a one to many relationship of different types in Entity Framework code first?

This is my design. I'm thinking of where a parent object has a collection of child objects, where each child object can be a different type of object stored in an independent table in the database.
In my design, each day is aggregated into a Report object assigned to a User. This Report object can have multiple Activities. However, these Activities can be different types of objects. Like one activity may be food and another activity may be exercise. I'm curious if there's another way around this relationship than my current EF design.
My Report object cannot navigate to the children. But each child, like DbSet or DbSet has a link to the parent Report object. It's important to have the Report object because it links to goal information and helps to establish a base for aggregating data against goals.
Is there a way to setup a parent object so that it can have a child collection with multiple child objects, or setup the mappings so that if the parent Report is deleted then this will cascade to the child activities? Or would you go about this in a different way? Thanks
Inheritance is what you can use to accommodate different types into a single collection. Create a base Activity type, put the common properties there (along with a navigation property to it's parent class) and then create one subtype for each different activity type and add it's specific properties.
I could not understand if the parent object and the report object are the same thing, so I will assume the aren't and define these two classes.
public class Parent
{
public int Id { get; set; }
public ICollection<Activity> Activities { get; set; }
}
public class Report
{
public int Id { get; set; }
}
public abstract class Activity
{
public int Id { get; set; }
public virtual Parent Parent { get; set; }
public virtual Report Report { get; set; }
// common activity properties
}
public class Food : Activity
{
// Food specific properties
}
public class Excercise : Activity
{
// Exercise specific properties
}
Then you can create a DbSet for the Parent, the Report and the Activity. There's no need to create dbsets for it's subtypes, but you can, if you wish so.
public DbSet<Parent> Parents { get; set; }
public DbSet<Report> Reports { get; set; }
public DbSet<Activity> Activities { get; set; }
You can query specific activity subtypes this way:
var indoorExercises = context.Activities.OfType<Exercise>().Where(e => e.IsIndoor);
You can get more information following this link: http://weblogs.asp.net/manavi/archive/2010/12/24/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph.aspx

Entity objects with helper properties

In my domain model I have an Entity object that looks as follows:
public class Group
{
public int idGroup { get; set; }
public string Description { get; set; }
}
I have a repository for this object:
public class GroupRepository : IGroupRepository
{
public Group LoadGroup(int idGroup)
{
//imitation of SQL data reader
Group g = new Group();
g.idGroup = Convert.ToInt32(r["idTipoGrupo"]);
g.Description = Convert.ToString(r["Descricao"]);
return g;
}
}
But now I need to get some extra information from data store about Group objects through a new function in my created repository, here are the fields I need:
public bool HasChildGroups { get; set; }
public int ChildGroupsCount { get; set; }
public bool HasDeals { get; set; }
public int DealsCount { get; set; }
These properties look to me like a "service" or "helper" properties and I don't plan to use them everywhere in my application, only few times, but I need them. The simplest thing I could think of is that I added these "service" properties to my Group object and created a method in my repository that populates them. But I consider doing this wrong, as it is the Entity and I don't need them in here. So where should I keep such "service" objects? Do I have to create a new class that inherits from Group like this:
public class GroupHelper : Group
{
public bool HasChildGroups { get; set; }
public int ChildGroupsCount { get; set; }
public bool HasDeals { get; set; }
public int DealsCount { get; set; }
}
Or should I consider using some Data Transfer Objects?
How would you solve this problem?
Any help appreciated.
The first question to ask is how the state of the proposed GroupHelper object is managed. Attributes such as HasChildGroups seems like they would be altered as a result of behaviors invoked on a Group entity. If so, then they should be first class entities in your domain model, perhaps event part of the group entity itself. If the properties are managed outside of your domain model then you can just query that data as you would any other external data source. I would have this be a standalone object, perhaps called something like GroupInfo not extending Group itself.
What seems to be the issue here is that you have query requirements that aren't in alignment with the shape of your entities. In that case you have the flexibility to decouple your read-models from your domain models. Read-models are intended to fulfill query requirements and your domain models are intended to host behavior associated with your domain.
HasChildGroups [...] look to me like a "service" or "helper" properties [...] But I consider doing this wrong, as it is the Entity and I don't need them in here.
If you concider your Group object to be a data access object and you have a separate model for, say, viewdata, you're right.
But this may also be a fat class, providing in view-specific and database-specific code. It's not plain wrong.
You could indeed create a GroupDTO class that provides the properties you require in the application but not for the data access, to separate concerns.

Fluent NHibernate - Query over a derived class

Lets say I have two classes:
public class A
{
public virtual int Id { get; set; }
public virtual Object1 Obj { get; set; }
}
public class B : A
{
public new virtual Object2 Obj { get; set; }
}
I use Fluent NHibernate and I have created two different mappings for the two classes. However, when I try to query class A in my repository, FNH finds both class B and A, which kind of makes sense since both are A.
Example (this criteria will query over both A and B):
public List<T> GetByName(string name)
{
return Session.CreateCriteriaOf<A>.Add(Restrictions...);
}
When writing CreateCriteriaOf<A>, I only want to query over A - not B. How can I solve my problem?
I think you better make an inheritance tree where both A and B derive from a common (abstract) base type. Then NHibernate can make the distinction by a discriminator column.
Of course, your data model should accommodate this, so I hope your model is not prescribed in any way.

Categories