Suppose you have sets of Fluent conventions that apply to specific groups of mappings, but not to all of them.
My thought here was, I'll create custom C# attributes that I can apply to the Fluent *Map classes - and write conventions that determine acceptance by inspecting the *Map class to see if the custom attribute was applied.
That way, I can select groups of conventions and apply them to various mappings by just tagging them with a custom attribute - [UseShortNamingConvention], etc.
I'm new to NHibernate (and Fluent, and C# for that matter) - is this approach possible?
And is it sane? :-)
Thanks!
Yes it is! Ive actually done something similiar but went with Marker Interfaces instead (INotCacheable, IComponent), but Marker Interface or Attribute, should't be that much of a difference.
When applying your conventions, just check for the presence of your attribute and ur good :)
EDIT:
Adding some code samples
public class MyMappingConventions : IReferenceConvention, IClassConvention
{
public void Apply(IOneToManyCollectionInstance instance)
{
instance.Key.Column(instance.EntityType.Name + "ID");
instance.LazyLoad();
instance.Inverse();
instance.Cascade.SaveUpdate();
if ((typeof(INotCacheable).IsAssignableFrom(instance.Relationship.Class.GetUnderlyingSystemType())))
return;
instance.Cache.ReadWrite();
}
public void Apply(IClassInstance instance)
{
instance.Table(instance.EntityType.Name + "s");
//If inheriting from IIMutable make it readonly
if ((typeof(IImmutable).IsAssignableFrom(instance.EntityType)))
instance.ReadOnly();
//If not cacheable
if ((typeof(INotCacheable).IsAssignableFrom(instance.EntityType)))
return;
instance.Cache.ReadWrite();
}
}
Related
I am using the new Test Doubles in EF6 as outlined here from MSDN . VS2013 with Moq & nUnit.
All was good until I had to do something like this:
var myFoo = context.Foos.Find(id);
and then:
myFoo.Name = "Bar";
and then :
context.Entry(myFoo).Property("Name").IsModified = true;
At this point is where I get an error:
Additional information: Member 'IsModified' cannot be called for
property 'Name' because the entity of type
'Foo' does not exist in the context. To add an
entity to the context call the Add or Attach method of
DbSet.
Although, When I examine the 'Foos' in the context with an AddWatch I can see all items I Add'ed before running the test. So they are there.
I have created the FakeDbSet (or TestDbSet) from the article. I am putting each FakeDbSet in the FakeContext at the constructor where each one gets initialized. Like this:
Foos = new FakeDbSet<Foo>();
My question is, is it possible to work with the FakeDbSet and the FakeContext with the test doubles scenario in such a way to have access to DbEntityEntry and DBPropertyEntry from the test double? Thanks!
I can see all items I Add'ed before running the test. So they are there.
Effectively, you've only added items to an ObservableCollection. The context.Entry method reaches much deeper than that. It requires a change tracker to be actively involved in adding, modifying and removing entities. If you want to mock this change tracker, the ObjectStateManager (ignoring the fact that it's not designed to be mocked at all), good luck! It's got over 4000 lines of code.
Frankly, I don't understand all these blogs and articles about mocking EF. Only the numerous differences between LINQ to objects and LINQ to entites should be enough to discourage it. These mock contexts and DbSets build an entirely new universe that's a source of bugs in itself. I've decided to do integrations test only when and wherever EF is involved in my code. A working end-to-end test gives me a solid feeling that things are OK. A unit test (faking EF) doesn't. (Others do, don't get me wrong).
But let's assume you'd still like to venture into mocking DbContext.Entry<T>. Too bad, impossible.
The method is not virtual
It returns a DbEntityEntry<T>, a class with an internal constructor, that is a wrapper around an InternalEntityEntry, which is an internal class. And, by the way, DbEntityEntry doesn't implement an interface.
So, to answer your question
is it possible to (...) have access to DbEntityEntry and DBPropertyEntry from the test double?
No, EF's mocking hooks are only very superficial, you'll never even come close to how EF really works.
Just abstract it. If you are working against an interface, when creating your own doubles, put the modified stuff in a seperate method. My interface and implementation (generated by EF, but I altered the template) look like this:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Model
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public interface IOmt
{
DbSet<DatabaseOmtObjectWhatever> DatabaseOmtObjectWhatever { get; set; }
int SaveChanges();
void SetModified(object entity);
void SetAdded(object entity);
}
public partial class Omt : DbContext, IOmt
{
public Omt()
: base("name=Omt")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<DatabaseOmtObjectWhatever> DatabaseOmtObjectWhatever { get; set; }
public void SetModified(object entity)
{
Entry(entity).State = EntityState.Modified;
}
public void SetAdded(object entity)
{
Entry(entity).State = EntityState.Added;
}
}
}
I see how I can use the mapping file to specify a custom IUserType for any nhibernate mapped class I want.
However, I don't want to type it in every time. Is there a way to override the standard mapping table seen here?
I have Jørn Schou-Rode's IUserType implementation for storing a guid in Binary(16) in MariaDB. All I want is to enter one or two lines of code to tell Nhibernate when it sees a System.Guid to convert it to the custom "BinaryGuidType" that Schou-Rode made me. Can it be done?
If you are using Fluent NHibernate you can easily do this using Conventions. Here is how I map all strings to varchar instead of nvarchar:
public class PropertyConvention : IPropertyConvention
{
public void Apply(IPropertyInstance instance)
{
SetStringsAsAnsiStringByDefault(instance);
}
private void SetStringsAsAnsiStringByDefault(IPropertyInstance instance)
{
if (instance.Property.PropertyType == typeof(string))
{
instance.CustomType("AnsiString");
}
else if (instance.Property.PropertyType == typeof(char))
{
instance.CustomType("AnsiChar");
}
}
}
I believe the later versions of NHibernate have in-built support for conventions, but the documentation seems to be sparse. Here is an article for you to get started though: http://weblogs.asp.net/ricardoperes/nhibernate-conventions
A common red flag that an OOP language is not being leveraged properly looks like this:
if (typeof(x) == T1)
{
DoSomethingWithT1(x);
}
else if (typeof(x) == T2)
{
DoSomethingWithT2(x);
}
The standard "fix" for such design issues is to make T1 and T2 both share an interface, either through inheritance of a base type or implementation of a common interface (in languages that support it); for example, in C# a solution might be:
public interface IT
{
void DoSomething();
}
However, sometimes you want to implement functionality that differs based on the type of an object but that functionality does not belong within that object's type; thus polymorphism seems the wrong way to go.
For example, consider the case of a UI that provides a view of a given clump of data. Supposing this view is capable of rendering various layouts and controls depending on the type of data being presented, how would you implement this type-specific rendering without a bunch of if/else statements?
For reasons that I hope are obvious, putting the rendering logic in the type itself strikes me as a very bad decision in this case. On the other hand, without coupling the type of data object to its visual presentation I have a hard time seeing how the if/else scenario is avoided.
Here's a concrete example: I work on a trading application which utilizes many different pricing models for various market products. These different models are represented by types inheriting from a common PricingModel base; and each type is associated with a completely different set of parameters. When the user wants to view the parameters for a particular pricing model (for a particular product), currently these are displayed by a form which detects the type of the model and displays an appropriate set of controls. My question is how this could be implemented more elegantly than it is currently (with a big if/else block).
I realize this probably seems like a very basic question; it's just one of those gaps in my knowledge (of solid OOP principles? design patterns? common sense?) that I figured it's about time to fix.
We are injecting (Spring.Net) such functionality into dictionaries by type.
IDictionary<Type, IBlahImplementor> blahImplementors;
blahImplementors[thingy.GetType()].Do(thingy);
This dictionary could be managed by a kind of repository which provides the functionality.
As an implementation detail, the implementor usually knows the type it depends on an can provide it itself:
interface IBlahImplementor
{
Type ForType { get; }
void Do(object thingy);
}
Then it is added to the dictionary like this:
IEnumerably<IBlahImplementor> blahImplementors;
foreach (var implementor in blahImplementors)
{
blahImplementors.Add(implementor.ForType, implementor);
}
Remark: IMHO, it is very important to understand that some things do NOT belong into a class, even if providing subtype-specific implementations would make life much easier.
Edit: Finally understood your concrete example.
It is actually about instancing the right UI control to show the pricing models parameters. It should be possible with the pattern I described above. If you don't have a single UI control for a pricing model, you either create it or you write a UI configurer or something like this which sets up the required controls.
interface IPricingModelUiConfigurer
{
Type PricingModelType { get; }
void SetupUi(Control parent, IPricingModel model);
}
you can use common interface approach as you describe and Command pattern to trigger methods with "functionality does not belong within that object's type". I think this won't break solid OOP principles.
What you described is pretty much exactly the use case for the Visitor Pattern.
EDIT: For your concrete example, you could apply the visitor pattern like this:
// interface used to add external functionality to pricing models
public interface PricingModelVisitor {
void visitPricingModel1(PricingModel1 m);
void visitPricingModel2(PricingModel2 m);
...
}
// your existing base-class, with added abstract accept() method to accept a visitor
public abstract class PricingModelBase {
public abstract void accept(PricingModelVisitor v);
...
}
// concrete implementations of the PricingModelBase implement accept() by calling the
// appropriate method on the visitor, passing themselves as the argument
public class PricingModel1 : PricingModelBase {
public void accept(PricingModelVisitor v) { v.visitPricingModel1(this); }
...
}
public class PricingModel2 : PricingModel {
public void accept(PricingModelVisitor v) { v.visitPricingModel2(this); }
...
}
// concrete implementation of the visitor interface, in this case with the new
// functionality of adding the appropriate controls to a parent control
public class ParameterGuiVisitor : PricingModelVisitor {
private Control _parent;
public ParameterGuiVisitor(Control parent) { _parent = parent; }
visitPricingModel1(PricingModel1 m) {
// add controls to _parent for PricingModel1
}
visitPricingModel2(PricingModel2 m) {
// add controls to _parent for PricingModel1
}
}
now, instead of using a big if-else block when you need to display the edit-controls for the parameters of a specific subtype of PricingModelVisitor, you can simply call
somePricingModel.accept(new ParameterGuiVisitor(parentControl))
and it will populate the appropriate GUI for you.
I have the following IIdConvention for a FluentNHibernate automapping. I want all of my id properties to use a custom type that is represented by a string property but the CustomType is never applied to my mappings.
public class PrimaryKeyHasTableName : FluentNHibernate.Conventions.IIdConvention
{
public void Apply(FluentNHibernate.Conventions.Instances.IIdentityInstance instance)
{
instance.Column(instance.EntityType.Name + "Id");
instance.CustomType<CustomIdType>();
}
}
When I looked into the FluentNHibernate source it appears that the Type for the id property has already been set so it is not being set by my convention.
If I use a ClassMap to map the class manually I have not problem setting the CustomType for the Identity property.
Id(x => x.Id)
.Column("UserId")
.CustomType<OnFileIdType>();
Does anybody know how I can successfully set the custom id property using a convention?
Or get my convention to run earlier in the mapping process so that the Type isn't already set by the time my code runs.
Also, here's my configuration code:
Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(connString))
.Mappings(m =>
{
m.FluentMappings.AddFromAssemblyOf<BaseEntity>();
m.AutoMappings.Add(AutoMap.AssemblyOf<BaseEntity>()
.Where(t => t.Namespace.EndsWith("Models.Domain"))
.Conventions.AddFromAssemblyOf<BaseEntity>()
.UseOverridesFromAssemblyOf<BaseEntity>()
);
})
.ExposeConfiguration(CreateSchema)
.BuildSessionFactory();
Thanks.
I don't think you can achieve what you want with conventions.
One thing you can try is having all your entities subclass from an abstract entity that defines the Id property and has the custom type mapping for it.
I wouldn't recommend this however, It will just open room for more automapping problems.
Just go for the manual CustomType for each class map.
I'm having the exact same problem, it would be great if FNH's IIdConvention supported this.
After trying a few things and reading this I have resigned myself to implementing IAutoMappingOverride for entities using a custom type for their Id.
public class ProductMap : IAutoMappingOverride<Product>
{
public void Override(AutoMapping<Product> mapping)
{
mapping.Id(x => x.Id).CustomType<ProductId>();
}
}
Using automapping override instead of ClassMap will continue to automap the rest of your properties. Alter your AutoMappings initialisation code to include
.Overrides.AddFromAssemblyOf<BaseEntity>()
I am getting the same problem. I believe that it is arising from the invocation of Conventions.AddFromAssemblyOf<BaseEntity>(), which is causing your custom convention to not be applied.
(By the way, the posted code will work only if your convention classes are in the same assembly as your BaseEntity - it might be safer to use Conventions.AddFromAssemblyOf<PrimaryKeyHasTableName>())
A bug was raised about AddFromAssemblyOf back in February 2011: Fluent NHibernate - Setting CutomType IIdConvention. There is no resolution posted.
The work-around appears to be to add each of the Conventions explicitly
Conventions.Add<PrimaryKeyHasTableName>()
To check this, you can add the following line after the line which adds the automappings, in order to export the mappings to an hbm.xml file on your hard drive, and take a look at the generated mappings.
m.AutoMappings.ExportTo(#"C:\ExportedMappings")
Also, I suggest you add a breakpoint into the Apply method and run the code to ensure that it is being invoked.)
I am retrofitting a very large application to use NHibernate as it's data access strategy. Everything is going well with AutoMapping. Luckily when the domain layer was built, we used a code generator. The main issue that I am running into now is that every collection is hidden behind a custom class that derives from List<>. For example
public class League
{
public OwnerList owners {get;set;}
}
public class OwnerList : AppList<Owner> { }
public class AppList<T> : List<T> { }
What kind of Convention do I have to write to get this done?
I don't think you're going to be able to achieve this with a convention. You will have to create an auto mapping override and then do the following:
mapping.HasMany(l => a.owners).CollectionType<OwnerList>();