Fluent NHibernate - Query over a derived class - c#

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.

Related

EF6 - BaseClass data duplication

I have a base class A and derived class B. B is introduced in my latest migration. I am going for a Table-per-Type inheritance. There can be many Bs for one A. The error I am getting when trying to update-database is related the Index on A.Designation, because the DB gets populated by the Seed method. I do understand where this error comes from, but I do not know how to avoid it.
The base class:
[Table("As")]
class A
{
[Key]
public Id { get; set; }
[Index(IsUnique = true)]
public string Designation { get; set; }
// This is mapped via EF and required by Bs constructor
public ICollection<SomeType> SomeType { get; set; }
// Parameter less constructor for EntityFramework
private A() { }
public A(string designation)
{
Designation = designation;
}
}
The derived class:
[Table("Bs")]
class B : A
{
public B(A a) : base(a.designation)
{
foreach (SomeType someType in A.SomeTypes)
{
// Do something
}
}
}
So in the Seed method first an instance a of A, then an instance b of B based on a is added to the DB.
As I understand it, calling new B(a) creates a new instance of A which also is added to the DB which fails because of the unique index.
How do I avoid this?
I want the data to be referenced, not duplicated. I guess it would be possible to use a Table-per-Hierarchy scheme but that would duplicate the data of A for each B, (right?) which I would like to avoid, especially because A.SomeEntities would have its entries duplicated as well.
Another possibility that just popped into my mind, is passing the the Id of a to b's constructor, but that would then have to call the DbContext and probably imply some other weirdness I am missing right now.
Looks like you are trying to link with existing object instead of class inheritance?
Why not create a link between your b and a?
[Table("Bs")]
class B
{
public A referredA {get;set;}
public B(A a)
{
referredA=a;
}
}

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.

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.

Implementing interfaces within interfaces

I'm writing some code for importing files which will import either delimited or fixed width files based on a template that describes the file layout.
I've created an interface IFileTemplate:
public interface IFileTemplate
{
string Name { get; set; }
bool IgnoreEmptyLines { get; set; }
}
which is used by a DelimitedFileTemplate class and a FixedWidthFileTemplate class.
I also have an interface for specifying each of the columns that make up a template:
public interface IFileTemplateColumn
{
int ID { get; set; }
string Name { get; set; }
bool Ignore { get; set; }
}
This interface is then used by a DelimitedTemplateColumn class and a FixedWidthTemplateColumn class.
As both the DelimitedFileTemplate and FixedWidthFileTemplate classes will have a list of columns I've made the list a member of the IFileTemplate column:
List<IFileTemplateColumn> Fields { get; set; }
My problem is when I've come to implement the list in the DelimitedFileTemplate and FixedWidthFileTemplate classes, for example:
public class FixedWidthFileTemplate : IFileTemplate
{
public int ID { get; set; }
public string Name { get; set; }
public List<FixedWidthFileTemplateColumn> Fields { get; set; }
}
If I try and implement List<IFileTemplateColumn> with List<DelimitedFileTemplateColumn> or List<FixedWidthFileTemplateColumn> then the compiler complains that they don't match List<IFileTemplateColumn>.
I can understand this but it seems wrong not to have the column list in the ITemplateInterface. The only get around I can think of is to have the Delimited and FixedWidth classes use List<IFileTemplateColumn> and have the property getter cast the list to the delimited or fixed width column list but there seems a bit of code smell to that. Can anyone suggest a better way for doing this?
A suitable and not smelly solution to this design problem are generics:
interface IFileTemplate<T> where T : IFileTemplateColumn
{
List<T> Fields { get; set; }
}
DelimitedFileTemplate implements IFileTemplate<DelimitedFileTemplateColumn> and so on.
Perhaps all the differences between the file templates could be sensibly defined by IFileTemplateColumn only and you could simplify things with FileTemplate<IFileTemplateColumn> insted of one FileTemplate class per one FileTemplateColumn class relation.
Update
As for the factory method: IFileTemplate<IFileTemplateColumn> Create: if the consumers of this method are supposed to be able to access the list of columns, the method signature will have to contain the concrete ColumnTemplate. For example:
DelimitedFileTemplate Create
or
interface IFactory<T> where T : IFileTemplateColumn
{
IFileTemplate<T> Create();
}
class DelimitedFactory : IFactory<DelimitedFileTemplateColumn>
{
IFileTemplate<DelimitedFileTemplateColumn> Create()
{
return new DelimitedFileTemplate();
}
}
If the consumers of the method won't be interested in the list, introduce a more general interface (much like IEnumerable<T> : IEnumerable):
interface IFileTemplate { ... }
interface IFileTemplate<T> : IFileTemplate where T : IFileTemplateColumn
{
List<IFileTemplateColumn> Columns { get; set; }
}
Then your IFileTemplate Create() method could return any of the concrete FileTemplate regardless of the column.
I've worked with this kind of generics usage and they might tend to propagate (in this example Column hierarchy will be duplicated in FileTemplate hierarchy and might be duplicated in the factory hierarchy). Sometimes this reveals some flaws in the design. If you were able to sensibly cut the IFileTemplate hierarchy to one base parametrized FileTemplate class, this was certainly the way to go. This is how I often use this: define the smallest parts, if the hierarchy tends to duplicate, some parts of the algorithms can be perhaps moved to the 'smallest-parts-classes'.

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.

Categories