Controlling TPT-mapping of properties in Entity Framework - c#

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.

Related

Fluent nHibernate - Mapping a polymorphic property to a single column in the table

I have something like the classes below, I'd like to map Foo to a single table with two columns, Id and State with values like 1, "BigState" and 2, "LittleState" but I'm really struggling to find examples of maps for this.
public class Foo
{
public int Id { get; set; }
public State State { get; set; }
}
public abstract class State
{
}
public class BigState : State
{
}
public class LittleState : State
{
}
https://nhibernate.info/doc/nhibernate-reference/inheritance.html
You are interested in table per class hierarchy strategy. Your second column would be discriminator column. When you are using FluentNhibernate you can derive from DefaultAutomappingConfiguration and override methods AbstractClassIsLayerSupertype, IsDiscriminated, GetDiscriminatorColumn. You also need to implement IClassConvention and ISubclassConvention to provide class name as discriminator value, something like that.
public class SubclassConvention : ISubclassConvention
{
public void Apply(ISubclassInstance instance)
{
instance.DiscriminatorValue(instance.EntityType.Name);
}
}

Nhibernate - Getting two object type in repository return result

I have two class BookingInfo.cs and BookingTransaction class.
public class BookingInfo
{
public virtual string Code { get; set; }
}
public class BookingTransaction : BookingInfo {
public virtual string CustomerRefNo { get; set; }
}
below is the NHibernate mapping for both classes
public class BookingInfoConfiguration : ClassMap<BookingInfo> {
public BookingInfoConfiguration() {
Table("Bkg_BookingInfo");
LazyLoad();
DynamicUpdate();
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
}
}
public class BookingTransactionConfiguration :
ClassMap<BookingTransaction> {
public BookingTransactionConfiguration() {
Table("Bkg_BookingInfo");
LazyLoad();
DynamicUpdate();
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
}
}
Now i am querying to get rows from database.
CurrentSession.Query<BookingInfo>().ToList();
I get two items for single row in database table. one for Bookinginfo and another for BookingTransaction. but i want to get only result of type Bookinginfo.
How to remove the items of the child class from the result?
As said in Rabban's answer, this is by design. This is called implicit polymorphism. Rabban propose you to change your class hierarchies, but you can instead disable implicit polymorphism if you prefer.
With hbm mappings (I do not use fluent and do not know it), add the attribute polymorphism="explicit" on your class.
Mapping by code supports it too on class mapper with .Polymorphism(PolymorphismType.Explicit).
You can read more about implicit/explicit polymorphism here:
Implicit polymorphism means that instances of the class will be
returned by a query that names any superclass or implemented interface
or the class and that instances of any subclass of the class will be
returned by a query that names the class itself. Explicit polymorphism
means that class instances will be returned only be queries that
explicitly name that class and that queries that name the class will
return only instances of subclasses mapped inside this <class>
declaration as a <subclass> or <joined-subclass>. For most purposes
the default, polymorphism="implicit", is appropriate. Explicit
polymorphism is useful when two different classes are mapped to the
same table (this allows a "lightweight" class that contains a subset
of the table columns).
Its intended that NHibernate returns you both objects. To prevent this behavior create a abstract base class where both other class derive. Then you don't need to duplicate code and you can query each class separately.
Create the base class:
public abstract class BookingBase
{
public virtual string Code { get; set; }
}
and then derive your classes from it:
public class BookingInfo : BookingBase
{
}
public class BookingTransaction : BookingBase
{
public virtual string CustomerRefNo { get; set; }
}
Your mappings and queries can remain the same. And if you want to query both classes with one query, just query BookingBase.

What is the purpose of virtual in Entity Framework?

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

Entity Framework Code First TPH inheritance - can different child classes share a field?

I have an Entity Framework Model created using Entity Framework Code First that is using Table Per Hierarchy inheritance where the structure looks a little like this:
public abstract class BaseState
{
public int Id { get; set; }
public string StateName { get; set; }
// etcetera
}
public class CreatedState : BaseState
{
public User Owner { get; set; }
}
public class UpdatedState : BaseState
{
public User Owner { get; set; }
}
Now what that creates is in my BaseStates table I have Owner_Id and Owner_Id1 stored. But given that no class will ever be both a CreatedState and an UpdatedState it seems as though it would be logical to use a single Owner_Id for both. Which would also make it easier to follow the database.
My basic question is: Is this possible with Code First EF4?
I have tried to map the columns:
public class CreatedState : BaseState
{
[Column("OwnerId")]
public User Owner { get; set; }
}
public class UpdatedState : BaseState
{
[Column("OwnerId")]
public User Owner { get; set; }
}
That appeared to have no effect.
Then I tried creating a shared parent class, which is probably more correct OO anyway:
public abstract class OwnedState : BaseState
{
public User Owner { get; set; }
}
public class CreatedState : OwnedState
{
}
public class UpdatedState : OwnedState
{
}
Again, no dice. Or, more worryingly, this appears to work in some cases and not in others ( obviously my real configuration is slightly more complex ) when I can see precisely no difference between the classes where it does work.
Edit for more detail on what fails:
I have two fields that behave in the way I have described above, we might call the associated classes OwnedState and ActivityState, both of which I have created as an abstract class in the way shown in my last example. OwnedState has two classes that derive from it, ActivityState has three. In the database I have ActivityState_Id but also OwnedState_Id and OwnedState_Id1.
I can see no difference at all between the OwnedState and ActivityState classes aside from the type that they reference ( both other entities ) and yet in the database it appears as though EF has somehow interpreted them differently- I don't understand the EF internals well enough to know how it makes that decision.
If you want to have one Owner_ID to have both CreatedState and UpdatedState to refer to, then the User Owner should be placed in the BaseState.
I don't know what you are trying to do with this, but logically, you wouldn't be having CreatedState and UpdatedState as classes, but more of values of State property (or column in database) to save the state (Created or Updated). But, again, maybe you are trying something else with this.. I guess.

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