Most optimal way to model a generic class in nHibernate - c#

Say I have a class something like...
public class SomeClass<T> where T : ISomeConstrainingInterface
{
public T MyPropertyOfTypeT {get;set;}
public int SomeIntProp {get;set;}
public string SomeStringProp {get;set;}
}
Where T can be a fairly small limited set (say 5 or 6 types)
What is the best and most efficient way to map this class in nHibernate ? (using fluentNHibernate)

this will create a seperate table for each type concreate of SomeClass, so there is no problem with different Id types and foreign keys are possible. SomeClass should implement an interface so all can be used be queried and handled generically.
public abstract class SomeClassMapBase<T> : ClassMap<SomeClass<T>>
{
public SomeClassMapBase()
{
Map(x => x.SomeIntProp);
Map(x => x.SomeStringProp);
}
}
public class SomeClassReferencedClassMap : SomeClassMapBase<ReferencedClass>
{
public SomeClassReferencedClassMap()
{
CompositeId()
.KeyReference(x => x.Referenced, "Refernece_id");
}
}

Related

How to map a calss that inherits an asbtract class and implements an interface at the same time in nHibernate?

Imagine we have this entities:
public interface ISomeone
{
}
public abstract class Parent
{
}
public class Child : Parent , ISomeone
{
}
public class Orphan : ISomeone
{
}
public class MyHeart
{
public ISomeone Person {get;set;}
}
then how is possible to mapping theses all classes in nhibernate?
I prefer to use separate tables for "Parent", "Orphane" and "MyHeart" class.
"Parent" , "Orphan" and "MyHeart" should be persist as aggrigate root and MyHeart could has a relation to any entity that implemented "ISomeone" interface. so it could expande across diffrent entity types with diffrent id form diffrent tables
Finally I've found the solution
the "Any" method is the answer, briefly with this method we define some meta value for each possible value for IPerson in another world every class that implements this interface should be define in "Any" method then nHibernate persists the Id and the MetaValue.
The mapping by code for my example would be like this:
public class MyHeartMapping : ClassMapping<MyHeart>
{
public MyHeartMapping()
{
Id(x => x.Id, x => x.Generator(Generators.Native));
Any(p => p.Person, typeof(long), m => {
m.MetaValue("Child", typeof(Child));
m.MetaValue("Orphane", typeof(Orphane));
m.Columns(i => i.Name("PersonId"), c => c.Name("ClassName")); });
}
}
public class ParentMapping : ClassMapping<Parent>
{
public ParentMapping()
{
Id(x => x.Id, x => x.Generator(Generators.Native));
Discriminator(c => c.Column("Discriminator"));
}
}
public class ChildMapping : SubclassMapping<Child>
{
public ChildMapping()
{
DiscriminatorValue("Child");
}
}
public class OrphaneMapping : ClassMapping<Orphane>
{
public OrphaneMapping()
{
Id(x => x.Id, x => x.Generator(Generators.Native));
}
}

Generic entity configuration class in EF Core 2

I'm trying to create a generic configuration class for my entities but i'm stuck.
I have an abstract class called EntityBase:
public abstract class EntityBase
{
public int Id { get; set; }
public int TenantId { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}
And many other classes that inherit from EntityBase, in which i have to configure the DateTime properties in each one with the same code. This way:
void EntityTypeConfiguration<MyEntity>.Configure(EntityTypeBuilder<MyEntity> builder)
{
builder.HasIndex(e => e.TenantId);
builder.Property(e => e.CreatedOn)
.ValueGeneratedOnAdd()
.HasDefaultValueSql("GETDATE()");
// Other specific configurations here
}
I would like to be able to call somthing like: builder.ConfigureBase() and avoid the code duplication. Any ideas?
There are several way you can accomplish the goal. For instance, since you seem to be using IEntityTypeConfiguration<TEntity> classes, you could create a base generic configuration class with virtual void Configure method and let your concrete configuration classes inherit from it, override the Configure method and call base.Configure before doing their specific adjustments.
But let say you want to be able to exactly call builder.ConfigureBase(). To allow that syntax, you can simply move the common code to a custom generic extension method like this:
public static class EntityBaseConfiguration
{
public static void ConfigureBase<TEntity>(this EntityTypeBuilder<TEntity> builder)
where TEntity : EntityBase
{
builder.HasIndex(e => e.TenantId);
builder.Property(e => e.CreatedOn)
.ValueGeneratedOnAdd()
.HasDefaultValueSql("GETDATE()");
}
}
with sample usage:
void IEntityTypeConfiguration<MyEntity>.Configure(EntityTypeBuilder<MyEntity> builder)
{
builder.ConfigureBase();
// Other specific configurations here
}

EF 6.1 Fluent API: Ignore property of the base class

I have a base class for all entities:
public class BaseClass
{
public int SomeProperty {get; set;}
}
public class SomeEntity : BaseClass
{
...
}
I want to ignore this property in some cases. Could I do in the OnModelCreating method something like this:
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Properties<int>()
.Where(p => p.Name == "SomeProperty")
.Ignore();
}
?
You could try:
modelBuilder.Entity<SomeEntity>().Ignore(p => p.SomeProperty);
It will cause SomeProperty not to be mapped to SomeEntity.
EDIT: If this property should never be mapped to database you can add NotMapped annotation in your BaseClass:
public class BaseClass
{
[NotMapped]
public int SomeProperty {get; set;}
}
This will be the same as ignoring this property in all extending classes.
Could you override it?
public class SomeEntity : BaseClass
{
[NotMapped]
public override int SomeProperty { get; set; }
...
}
A late entry here - but in case it's useful...
Having recently encountered similar requirements, I went with this:-
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Types<EntityBase>()
.Configure(config => config.Ignore(x => x.SomeBaseClassPropertyToIgnore));
}
}
This will apply the given configuration to all entity types that inherit from EntityBase. The same technique can be used to configure entity types based on an interface they implement (probably a better approach anyway).
Advantages are:-
No need to write and maintain the same config code for multiple concrete entities.
No need for [NotMapped] attribute, which is less flexible and adds potentially unwanted dependencies.
Note that the targeted types can be filtered further if necessary:-
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Types<EntityBase>().Where(t => t != typeof(SpecialExceptionEntity)).Configure(...);
}
Refs:-
https://msdn.microsoft.com/en-us/library/dn235653(v=vs.113).aspx
https://msdn.microsoft.com/en-us/library/dn323206(v=vs.113).aspx

Mapping Id attribute by Reflection

I'm trying to map the Id attribute from my entity classes with reflection using FluentNHibernate.
My entities:
public abstract class BaseEntity
{
public int Id { get; set; }
}
public class Entity : BaseEntity
{
public string Name { get; set; }
}
Ok, my mapping class is like above:
public class BaseMapping<E> : ClassMap<E>
{
public BaseMapping(string schema, string table)
{
Schema(schema);
Table(table);
Id(model => typeof(E).GetProperty("Id", typeof(int)), "Id")
.GeneratedBy.Identity()
.Not.Nullable();
}
}
public class EntityMapping : BaseMapping<Entity>
{
public EntityMapping() : base("dbo", "Entities")
{
Map(model => model.Name, "Name")
.Length(50)
.Insert().Update()
.Not.Nullable();
}
}
I am receiving this exception:
{"Identity type must be integral (int, long, uint, ulong)"}
When I map the Id attribute on the EntityMapping class...
Id(model => model.Id, "Id")
.GeneratedBy.Identity()
.Not.Nullable();
It's works like a charm. But the first attempt is not working.
Firstly your properties should be marked as virtual for your entities. This is so the NHibernate framework can perform its magic lazy loading voodoo.
That being said. Lets assume all your entities derive from BaseEntity as it appears. Because of this assumption you can let the typeparam E understand that it will always be a BaseEntity.
Once you do this you can then rewrite the BaseMapping<E> method as such.
public class BaseMapping<E> : ClassMap<E>
where E: BaseEntity
{
public BaseMapping(string schema, string table)
{
Schema(schema);
Table(table);
Id(model => model.Id, "Id");
}
}
By specifing where E: BaseEntity will expose the properties of E to your method. I have only tested this code up to the point of the mapping methods completing for multiple entity types.
As for why you recieved your message the statement
typeof(E).GetProperty("Id", typeof(int))
returns a type of PropertyInfo where you need to pass the member expression for the memberExpression parameter. By digging through the source of FluentNHibernate they use the Expression to evaluate to a Member through reflection.

How to declare a generic constraint that is a generic type

I have a two generic abstract types: Entity and Association.
Let's say Entity looks like this:
public class Entity<TId>
{
//...
}
and Association looks like this:
public class Association<TEntity, TEntity2>
{
//...
}
How do I constrain Association so they can be of any Entity?
I can accomplish it by the following:
public class Association<TEntity, TId, TEntity2, TId2>
where TEntity : Entity<TId>
where TEntity2: Entity<TId2>
{
//...
}
This gets very tedious as more types derive from Association, because I have to keep passing down TId and TId2. Is there a simpler way to do this, besides just removing the constraint?
This problem is usually solved by having your generic class (Entity<TId>, in this case) inherit from a common non-generic class.
public abstract class EntityBase
{
}
public class Entity<TId> : EntityBase
{
}
This will allow you to do:
public class Association<TEntity, TEntity2>
where TEntity : EntityBase
where TEntity2 : EntityBase
{
}
Edit
If having them inherit from a common class is an issue, then this could be easily done with an interface as well.
If the Id types are important inside the Association definition, you could create an enclosing "context":
public static partial class EntityIds<TId1, TId2> {
public class Association<TEntity1, TEntity2>
where TEntity1 : Entity<TId1>
where TEntity2 : Entity<TId2>
{
// ...
}
}
This way, the Association class declaration is still intelligible, and it retains the necessary type arguments for its type parameters.
A factory method could help you with the normal case:
public static class AssociationFactory {
public static EntityIds<TId1, TId2>.Association<Entity<TId1>, Entity<TId2>> Create<TId1, TId2>(/*params...*/) {
return new EntityIds<TId1, TId2>.Association<Entity<TId1>, Entity<TId2>>(/*params...*/);
}
}
It that looks like too much, and if you don't have entity specializations, you could model the association differently:
public class Association<TId1, TId2>
{
// ...
Entity<TId1> Entity1 { get; set; }
Entity<TId2> Entity2 { get; set; }
// ...
}

Categories

Resources