NHibernate: Persist Reference to Interface with Multiple Contrete Classes - nhibernate

I have a 1-to-many relationship between the RestorableEnvironment and IBaselineEntity objects: a given RestorableEnvironment will have one and only one IBaselineEntityobject, but each IBaselineEntity object may be tied to 0-n RestorableEnvironment objects. However, IBaselineEntity is implemented in one of two ways: via a file or via a database. My classes are (generally) like:
public interface IBaselineEntity
{
BaselineImage BuildImage();
//Remainder of interface
}
public class BaselineFile : IBaseline
{
//implementation
}
public class BaselineDatabase : IBaseline
{
//implementation
}
public class RestorableEnvironment
{
public IBaselineEntity BaselineEntity { get; set; }
//Remainder of class
}
NHibernate needs the concrete implementation of the IBaselineEntity in the references statement. To handle that, I have updated RestorableEnvironment to:
public class RestorableEnvironment
{
public IBaselineEntity BaselineEntity
{
get { return BaselineDatabase ?? BaselineFile; }
set
{
BaselineFile = value as BaselineFile;
BaselineDatabase = value as BaselineDatabase;
}
}
private BaselineFile _baselineFile;
public BaselineFile BaselineFile
{
get { return _baselineFile; }
protected set
{
_baselineFile = value;
if (value != null)
BaselineDatabase = null;
}
}
private BaselineDatabase _baselineDatabase;
public BaselineDatabase BaselineDatabase
{
get { return _baselineDatabase; }
protected set
{
_baselineDatabase= value;
if (value != null)
BaselineFile = null;
}
}
// Remainder of class
}
Now that I have concrete classes, I can now map in NHibernate, but this feels like a hack. Are there any suggestions for an improvement?

map it as any reference
using fluentmapping
// ClassMap<RestorableEnvironment>
RestorableEnvironmentMap()
{
ReferenceAny(e => e.BaselineEntity)
.EntityIdentifierColumn("entirtyid")
.EntityTypeColumn("entitytype")
.IdentityType<int>()
.MetaType<string>()
.AddMetaValue<E1>("e1")
.AddMetaValue<E2>("e2");
}

Related

(Polymorphism) Addition parameter pass to constructor of derived class in factory pattern

In factory pattern, we use a Factory class to produce a Product class that implement Abstract Product.
interface AbstractProduct {
public string getDetail();
}
class Product_A : AbstractProduct {
public string getDetail();
}
class Product_B : AbstractProduct {
public string getDetail();
}
class Factory {
public AbstractProduct produce(int product_id){
if (product_id == 1){
return Product_A();
}
else if (product_id == 2){
return Product_B();
}
}
}
int main() {
Factory factory = new Factory();
int id; // a random number either 1 or 2
print(factory.produce(id).getDetail());
}
My question is, what if today we need extract information to pass into Product_B from main(), for example a reference of a class instance.
int main() {
// object that need to be passed into Product_B
Database database = new Database();
Factory factory = new Factory();
int id; // a random number either 1 or 2
print(factory.produce(id).getDetail());
}
class Product_B : AbstractProduct {
public string getDetail() {
// I need the reference of database here.
// I'm unable to instance a database in side Product_B.
// I need to somehow pass it into Product_B.
database.query();
}
}
The only solution come to my mind is...
class Factory {
// pass the reference here
public AbstractProduct produce(int product_id, Database db){
if (product_id == 1){
return Product_A();
}
else if (product_id == 2){
return Product_B(db);
}
}
}
Is there any good solution or relative design pattern can solve this problem Elegant and Clean ? Thanks a lot.
The downside with your solution is that, every client of the Factory must have a Database in order to call the produce method.
So you can use the Abstract Factory pattern here:
interface AbstractFactory {
AbstractProduct produce();
}
class Factory_A implements AbstractFactory {
AbstractProduct produce() { return new Product_A(); }
}
class Factory_B implements AbstractFactory {
private Database db;
public Factory_B(Database db) { this.db = db; }
AbstractProduct produce() { return new Product_B(db); }
}
class Client {
private AbstractFactory factory;
public Client(AbstractFactory factory) { this.factory = factory; }
public void foo() {
AbstractProduct product = factory.produce();
// ...
}
}
void main() {
AbstractFactory factory = random() == 1 ?
new Factory_A() :
new Factory_B(new Database(...));
print(factory.produce().getDetail());
Client client = new Client(factory);
client.foo();
}
Hope this helps.

How to implement EF Code First and WCFDataService

A bit of history first. I created a EF Code First Library that contains POCO Objects as my Models, a generic DataProvider that inherits from DbContext, generic Repostory that implements the generic DataProvider, and a generic Service that implements the repository. I have used this library successfully in WPF (MVVM), ASP.Net, Window Forms, and ASP MVC applications.
For this discussion I will reference the Company Model
From the top down, I create a Service class called CompanyService that inherits from a base Service Class. The CompanyService class contains all of the business logic for the Company Model. This class uses the Repository class to perform the CRUD operations. The Repository then encapsulates all the DataProvider class operations.
I have done some research on using EF with WCFDataService, but I can't get my head around how to implement my library with it, particulary when it comes to overriding the CreateDataSource() Method.
It may be that I should just use a WCF Service instead, maybe I'm not understanding the purpose of the WCFDataService.
I have listed partial code for the classes involved:
public class CompanyService : ServiceBase<Company> ,ICompanyService
{
public Company GetCompanyByFolderId(string eFolderId)
{
return (Company)GetModelByFolderId(eFolderId);
}
}
public abstract class ServiceBase<TModel> : IService<TModel> where TModel : class, IModel
{
private IDataProvider _dataProvider;
public IDataProvider DataProvider
{
get
{
if (_dataProvider == null)
{
string connectionStringName = Properties.Settings.Default.DataProvider;
bool enableLazyLoading = true;
_dataProvider = new DataProvider(connectionStringName, enableLazyLoading);
}
return _dataProvider;
}
set
{
_dataProvider = value;
}
}
private IRepository<TModel> _repository;
public IRepository<TModel> Repository
{
get
{
if (_repository == null)
{
_repository = new Repository<TModel>(DataProvider);
}
return _repository;
}
set
{
_repository = value;
}
}
public TModel GetModelByFolderId(String folderId)
{
return GetTable().FirstOrDefault(o => o.EFolderid == folderId);
}
public virtual IQueryable<TModel> GetTable()
{
return Repository.GetTable();
}
}
public class Repository<TModel> : IRepository<TModel> where TModel : class, IModel
{
private IDataProvider _dataProvider;
public Repository(IDataProvider dataProvider)
{
_dataProvider = dataProvider;
}
private IDbSet<TModel> DbSet
{
get
{
return _dataProvider.Set<TModel>();
}
}
public IQueryable<TModel> GetTable()
{
return _dataProvider.GetTable<TModel>();
}
}
public class DataProvider : DbContext, IDataProvider
{
public DataProvider()
{
}
public DataProvider(string connectionStringName, bool enableLazyLoading = true)
: base(connectionStringName)
{
Configuration.LazyLoadingEnabled = enableLazyLoading;
//Configuration.ProxyCreationEnabled = false;
}
public new IDbSet<TModel> Set<TModel>() where TModel : class
{
return base.Set<TModel>();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CompanyMapping());
base.OnModelCreating(modelBuilder);
}
public IQueryable<TModel> GetTable<TModel>() where TModel : class
{
return Set<TModel>().AsQueryable();
}
}
Then my Test looks something like this:
[TestClass()]
public class CompanyServiceTest
{
[TestMethod()]
public void GetCompanies()
{
CompanyService target = new CompanyService();
IQueryable<Company> companies = target.GetTable();
Assert.IsNotNull(companies);
}
[TestMethod()]
public void GetCompanyByFolderId()
{
CompanyService target = new CompanyService();
Company company = target.GetCompanyByFolderId("0000000000000000000000000172403");
Assert.IsNotNull(company);
}
}

Cannot extend unmapped class: Entity

I have a base class called Entity:
public class Entity
{
public int Id {get;set;}
}
Let's say I have a class called Customer:
public class Customer : Entity
{
public string Name {get;set;}
}
Now, using convention based mapping by code in NHibernate 3.3.1, I try the following:
public static class DataHelper
{
private static HbmMapping GetMappings()
{
var mapper = new CustomModelMapper(typeof(Entity));
return mapper.CompileMappingFor(
typeof(DataHelper).Assembly.GetExportedTypes()
.Where(x => x.IsSubclassOf(typeof(Entity))));
}
}
When I try to run my app, I get the error "Cannot extend unmapped class: Entity". I don't want to map the Entity class - it's just a base class for inheriting some common properties. How can I tell NHibernate to ignore the unmapped class? For reference, my CustomModelMapper class is listed below.
The code for my CustomModelMapper class is listed below for reference
internal class CustomModelMapper : ConventionModelMapper
{
private const int DEFAULT_STRING_LENGTH = 100;
private Type baseType;
public CustomModelMapper(Type baseType)
{
this.baseType = baseType;
}
public CustomModelMapper()
{
SetupInspectors();
}
protected override void AppendDefaultEvents()
{
base.AppendDefaultEvents();
BeforeMapClass += OnBeforeMapClass;
BeforeMapProperty += OnBeforeMapProperty;
BeforeMapManyToOne += OnBeforeMapManyToOne;
BeforeMapBag += OnBeforeMapBag;
BeforeMapList += OnBeforeMapList;
BeforeMapSet += OnBeforeMapSet;
}
protected void OnBeforeMapClass(IModelInspector modelInspector, Type type, IClassAttributesMapper classCustomizer)
{
classCustomizer.Id(type.GetProperty("Id"), m => m.Generator(Generators.Native));
}
protected void OnBeforeMapProperty(IModelInspector modelInspector, PropertyPath member, IPropertyMapper propertyCustomizer)
{
if (member.LocalMember.GetPropertyOrFieldType().IsEnum)
{
var type = member.LocalMember.GetPropertyOrFieldType();
var genericType = typeof(EnumStringType<>).MakeGenericType(type);
propertyCustomizer.Type(genericType, null);
}
if (member.LocalMember.GetPropertyOrFieldType() == typeof(string))
propertyCustomizer.Length(DEFAULT_STRING_LENGTH);
}
protected void OnBeforeMapManyToOne(IModelInspector modelInspector, PropertyPath member, IManyToOneMapper propertyCustomizer)
{
propertyCustomizer.Cascade(Cascade.All);
propertyCustomizer.Fetch(FetchKind.Join);
propertyCustomizer.Lazy(LazyRelation.NoLazy);
propertyCustomizer.Index(string.Format("IX{0}{1}",
member.GetContainerEntity(modelInspector).Name,
member.LocalMember.Name));
}
protected void OnBeforeMapBag(IModelInspector modelInspector, PropertyPath member, IBagPropertiesMapper propertyCustomizer)
{
propertyCustomizer.Cascade(Cascade.All);
propertyCustomizer.Lazy(CollectionLazy.Extra);
propertyCustomizer.Fetch(CollectionFetchMode.Subselect);
}
protected void OnBeforeMapList(IModelInspector modelInspector, PropertyPath member, IListPropertiesMapper propertyCustomizer)
{
propertyCustomizer.Cascade(Cascade.All);
propertyCustomizer.Lazy(CollectionLazy.Extra);
propertyCustomizer.Fetch(CollectionFetchMode.Subselect);
}
protected void OnBeforeMapSet(IModelInspector modelInspector, PropertyPath member, ISetPropertiesMapper propertyCustomizer)
{
propertyCustomizer.Cascade(Cascade.All);
propertyCustomizer.Lazy(CollectionLazy.Extra);
propertyCustomizer.Fetch(CollectionFetchMode.Subselect);
}
protected void SetupInspectors()
{
IsRootEntity((type, declared) =>
{
return baseType.Equals(type.BaseType);
});
IsEntity((type, declared) =>
{
return baseType.IsAssignableFrom(type) && !type.IsInterface;
});
IsVersion((member, declared) =>
{
return
member.Name == "Version" &&
member.MemberType == MemberTypes.Property &&
member.GetPropertyOrFieldType() == typeof(int);
});
IsBag((member, declared) =>
{
if (member.GetPropertyOrFieldType().IsGenericType)
return IsGenericType(member, typeof(ICollection<>));
return false;
});
IsList((member, declared) =>
{
if (member.GetPropertyOrFieldType().IsGenericType)
return IsGenericType(member, typeof(IList<>));
return false;
});
IsSet((member, declared) =>
{
if (member.GetPropertyOrFieldType().IsGenericType)
return IsGenericType(member, typeof(ICG.ISet<>));
return false;
});
}
protected static bool IsGenericType(MemberInfo member, Type targetType)
{
var type = member.GetPropertyOrFieldType();
var generics = type.GetGenericInterfaceTypeDefinitions();
return generics.Contains(targetType);
}
}
The problem is probably with your IsEntity convention. Currently, it will return true for Entity class itself. Just add another check:
IsEntity((type, declared) =>
{
return baseType.IsAssignableFrom(type) && !type.IsInterface &&
type != typeof(Entity); // <- skip Entity class
});
Edit
Also, you have two constructors in your CustomModelMapper class. One of them accepts base type, the other one is default and calls SetupInspectors(). As I can see, your default constructor will never be called, since you are calling the one that accepts the base type, and it doesn't call the default constructor...
And the consequence of that is... your SetupInspectors() method will also never be called.

How do I map an Enumeration class without the discriminator being passed into the constructor?

Based on Jimmy's Enumeration classes idea I am wanting to see if I can avoid using the constructor to instantiate my type (which I assume is happening with the discriminator-value) but rather use a "factory method"-esque way of getting my instance mapped from the db.
Here is my type:
public class Impact : Enumeration
{
public static readonly Impact Carbon
= new Impact(1, "Carbon dioxide equivalent", CommonUnit.CO2e);
public static readonly Impact Energy
= new Impact(2, "Energy", CommonUnit.MJ);
public static readonly Impact Cost
= new Impact(3, "Cost", CommonUnit.Dollars);
public Impact(int index, string name, CommonUnit unit)
: base(index, name)
{
this.Unit = unit;
}
public CommonUnit Unit { get; private set; }
}
And here is the definition for Enumeration:
public class Enumeration : ValueObject
{
public Enumeration(int index, string displayName)
{
this.Index = index;
this.DisplayName = displayName;
}
public int Index { get; private set; }
public string DisplayName { get; private set; }
public override string ToString()
{
return this.DisplayName;
}
public static IEnumerable<T> GetAllFor<T>() where T : Enumeration
{
foreach (var publicStatic in typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly))
{
Enumeration item = null;
item = (Enumeration)publicStatic.GetValue(null);
yield return item as T;
}
}
public static T With<T>(int index) where T : Enumeration
{
return GetAllFor<T>().SingleOrDefault(i => i.Index == index);
}
}
ValueObject simply covers off Equality functionality.
Elsewhere I use the static methods to get items from this enum (kinda like how you could use the core Enumeration static methods):
impact = Impact.With<Impact>(index.ImpactId.Value);
This is pretty handy but I want to know if I can get NHibernate to do this too when rehydrating objects.
Can it be done and how?
With an NHibernate Custom Type:
public class EnumerationType<T> : PrimitiveType where T : Enumeration
{
public EnumerationType()
: base(new SqlType(DbType.Int32))
{
}
public override object Get(IDataReader rs, int index)
{
object o = rs[index];
var value = Convert.ToInt32(o);
return Enumeration.With<T>(value);
}
public override object Get(IDataReader rs, string name)
{
int ordinal = rs.GetOrdinal(name);
return Get(rs, ordinal);
}
public override Type ReturnedClass
{
get { return typeof(T); }
}
public override object FromStringValue(string xml)
{
return int.Parse(xml);
}
public override string Name
{
get { return "Enumeration"; }
}
public override void Set(IDbCommand cmd, object value, int index)
{
var parameter = (IDataParameter)cmd.Parameters[index];
var val = (Enumeration)value;
parameter.Value = val.Value;
}
public override string ObjectToSQLString(object value, Dialect dialect)
{
return value.ToString();
}
public override Type PrimitiveClass
{
get { return typeof(int); }
}
public override object DefaultValue
{
get { return 0; }
}
}
If you're doing an HBM.xml-based mapping, you can set the custom type like this:
<property name="Impact" column="Impact" type="Namespace.To.EnumerationType`1[[Impact, AssemblyWithDomainEnum]], AssemblyWithNHibCustomType"/>
Alternatively, if you're using Fluent NHibernate, you can create a convention to map all enumeration types without having to configure each one individually:
public class EnumerationTypeConvention : IPropertyConvention, IPropertyConventionAcceptance
{
private static readonly Type _openType = typeof(EnumerationType<>);
public void Apply(IPropertyInstance instance)
{
var closedType = _openType.MakeGenericType(instance.Property.PropertyType);
instance.CustomType(closedType);
}
public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
{
criteria.Expect(x => typeof(Enumeration).IsAssignableFrom(x.Property.PropertyType));
}
}
And then add that convention however you like in your Fluent NHibernate configuration.
This seemed to work too, but perhaps Jimmy's way seems easier:
public class ImpactEnumType : IUserType
{
public SqlType[] SqlTypes
{
get
{
//We store our Impact in a single column in the database that can contain a int (for the index value)
SqlType[] types = new SqlType[1];
types[0] = new SqlType(DbType.Int32);
return types;
}
}
public Type ReturnedType
{
get { return typeof(Impact); }
}
public bool Equals(object x, object y)
{
// Impact is derived from ValueObject which implements Equals
return x.Equals(y);
}
public int GetHashCode(object x)
{
// as above
return x.GetHashCode();
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
//We get the string from the database using the NullSafeGet used to get ints
int impactIndex = (int)NHibernateUtil.Int32.NullSafeGet(rs, names[0]);
// then pull the instance from the Enumeration type using the static helpers
return Impact.With<Impact>(impactIndex);
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
//Set the value using the NullSafeSet implementation for int from NHibernateUtil
if (value == null)
{
NHibernateUtil.Int32.NullSafeSet(cmd, null, index);
return;
}
value = (value as Impact).Index;
NHibernateUtil.Int32.NullSafeSet(cmd, value, index);
}
public object DeepCopy(object value)
{
//We deep copy the Impact by creating a new instance with the same contents
if (value == null) return null;
return Impact.With<Impact>((value as Impact).Index);
}
public bool IsMutable
{
get { return false; }
}
public object Replace(object original, object target, object owner)
{
//As our object is immutable we can just return the original
return original;
}
public object Assemble(object cached, object owner)
{
//Used for casching, as our object is immutable we can just return it as is
return cached;
}
public object Disassemble(object value)
{
//Used for casching, as our object is immutable we can just return it as is
return value;
}
}
My HBM XML:
<property name="Impact" column="ImpactIndex" type="namespace.childnamespace.ImpactEnumType, namespace.childnamespace" />

Ninject Intercept any method with certain attribute?

How can I get Ninject.Extensions.Interception to basically let me bind a specific interceptor to any method that has an attribute... psudocode:
Kernel.Intercept(context => context.Binding.HasAttribute<TransactionAttribute>())
.With<TransactionInterceptor>
With a class like:
public SomeClass
{
[TransactionAttribute]
public void SomeTransactedMethod()
{ /*do stuff */ }
}
Assuming that you are using Ninject.Extensions.Interception this should do the trick
public class TransactionInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
// Do something...
}
}
public class TransactionAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return new TransactionInterceptor();
}
}
public class SomeClass
{
[Transaction]
public virtual void SomeTransactedMethod() { }
}
Make sure that the method that should be intercepted is marked as virtual.
When SomeTransactedMethod() is called it should be intercepted.
var kernel = new StandardKernel();
kernel.Bind<SomeClass>().ToSelf();
var someClass = kernel.Get<SomeClass>();
someClass.SomeTransactedMethod();
UPDATE
You could create a custom planning strategy.
public class CustomPlanningStrategy<TAttribute, TInterceptor> :
NinjectComponent, IPlanningStrategy
where TAttribute : Attribute
where TInterceptor : IInterceptor
{
private readonly IAdviceFactory adviceFactory;
private readonly IAdviceRegistry adviceRegistry;
public CustomPlanningStrategy(
IAdviceFactory adviceFactory, IAdviceRegistry adviceRegistry)
{
this.adviceFactory = adviceFactory;
this.adviceRegistry = adviceRegistry;
}
public void Execute(IPlan plan)
{
var methods = GetCandidateMethods(plan.Type);
foreach (var method in methods)
{
var attributes = method.GetCustomAttributes(
typeof(TAttribute), true) as TAttribute[];
if (attributes.Length == 0)
{
continue;
}
var advice = adviceFactory.Create(method);
advice.Callback = request => request.Kernel.Get<TInterceptor>();
adviceRegistry.Register(advice);
if (!plan.Has<ProxyDirective>())
{
plan.Add(new ProxyDirective());
}
}
}
}
private static IEnumerable<MethodInfo> GetCandidateMethods(Type type)
{
var methods = type.GetMethods(
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance
);
return methods.Where(ShouldIntercept);
}
private static bool ShouldIntercept(MethodInfo methodInfo)
{
return methodInfo.DeclaringType != typeof(object) &&
!methodInfo.IsPrivate &&
!methodInfo.IsFinal;
}
}
This should now work.
var kernel = new StandardKernel();
kernel.Components.Add<IPlanningStrategy,
CustomPlanningStrategy<TransactionAttribute, TransactionInterceptor>>();
kernel.Bind<SomeClass>().ToSelf();
var someClass = kernel.Get<SomeClass>();
someClass.SomeTransactedMethod();
Here is the code that I used for the same purpose
//Code in Bind Module
this.Bind(typeof(ServiceBase<,>))
.ToSelf()
.InRequestScope()
.Intercept()
.With<TransactionInterceptor>();
And
public class TransactionInterceptor : IInterceptor
{
#region Constants and Fields
public ISession session;
private ISessionFactory sessionFactory;
#endregion
#region Constructors and Destructors
public TransactionInterceptor(ISession session, ISessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
this.session = session;
}
#endregion
public void Intercept(IInvocation invocation)
{
try
{
if (!session.IsConnected)
session = sessionFactory.OpenSession();
session.BeginTransaction();
invocation.Proceed();
if (this.session == null)
{
return;
}
if (!this.session.Transaction.IsActive)
{
return;
}
else
{
this.session.Transaction.Commit();
}
}
catch (Exception)
{
if (this.session == null)
{
return;
}
if (!this.session.Transaction.IsActive)
{
return;
}
this.session.Transaction.Rollback();
throw;
}
}
}
And code for TransactionAttribute
public class TransactionAttribute : InterceptAttribute
{
#region Public Methods
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return request.Context.Kernel.Get<TransactionInterceptor>() ;
}
#endregion
}