I'm using v2.1 of NHibernate.dll and NHibernate.Mappings.Attributes v2.1 in a project.
When I run the code further below, I get the following exception, and will be grateful for any pointers. On the same project, if I remove the attributes and use xml mapping files, it works fine.
NHibernate.MappingException was unhandled
Message="Could not compile the mapping document:
DomainModel.hbm.xml"
Source="NHibernate"
InnerException: System.NullReferenceException
Message="Object reference not set to an instance of an object."
Source="NHibernate"
StackTrace:
at NHibernate.Cfg.XmlHbmBinding.ClassBinder.BindClass
(XmlNode node, PersistentClass model)
at NHibernate.Cfg.XmlHbmBinding.RootClassBinder.Bind
(XmlNode node, HbmClass classSchema)
at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.AddRootClasses(XmlNode
parentNode)
at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.Bind(XmlNode node)
at NHibernate.Cfg.Configuration.AddValidatedDocument(NamedXmlDocument doc)
InnerException:
I have a contact class as follows (Domain class has just one method, no properties):
[NHibernate.Mapping.Attributes.Class]
public class Contact : DomainClass
{
[NHibernate.Mapping.Attributes.Id(Name = "Id")]
[NHibernate.Mapping.Attributes.Generator(1, Class ="Identity")]
public virtual int ID { get; set; }
[NHibernate.Mapping.Attributes.Property]
public virtual string Name { get; set; }
[NHibernate.Mapping.Attributes.Property]
public virtual string Town { get; set; }
}
and session code as follows:
Configuration cfg = new Configuration();
cfg.Configure();
cfg.AddInputStream(NHibernate.Mapping.Attributes.HbmSerializer.Default.Serialize(
typeof(Contact).Assembly), "DomainModel.hbm.xml");
_sessionFactory=cfg.BuildSessionFactory();
My hibernate.cfg.xml file is:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</
property>
<property name="connection.connection_string">Server=SERVER
\EXPRESS2008;Initial Catalog=Contacts;Integrated Security=True</property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFac tory, NHibernate.ByteCode.LinFu</property>
</session-factory>
</hibernate-configuration>
Stuart,
As I understand it,"DomainModel.hbm.xml" is the file NHibernate.Mappings.Attributes should create - the exception happens before the file is created (it's not in the output directory) and so unfortunately I can't post it.
Stuart,
Thanks again for your response.
Managed to get it to work using:
using (MemoryStream stream = new MemoryStream())
{
HbmSerializer.Default.HbmNamespace = "NSpace.DomainLayer.Entities";
HbmSerializer.Default.HbmAssembly = "NSpace";
HbmSerializer.Default.Serialize(stream,
System.Reflection.Assembly.GetExecutingAssembly());
stream.Position = 0;
Configuration cfg = new Configuration();
cfg.Configure();
cfg.AddInputStream(stream);
_sessionFactory = cfg.BuildSessionFactory();
}
and specifying table names in class attributes (my oversight as these were different from class names!).
Not sure why we need to specify Namespace separately, as I assumed NHibernate could work out the types to serialize from the assembly.
Hope above helps anyone experiencing similar issue, although my impression is few people are using NHibernate.Mappings.Attributes. The documentation seems to be seriously lacking.
Whenever you use hbm.xml file you will set your configuration class like this:
Configuration cfg = new Configuration();
cfg.Configure();
// Add class mappings to configuration object
cfg.AddAssembly(Assembly.GetCallingAssembly());
ISessionFactory sessionFactory = cfg.BuildSessionFactory();
Whenever you use Nhibernate.Mapping.Attributes like classe you will use:
For example you have use Mapping.attributes in Product Class
Configuration cfg = new Configuration();
cfg.Configure();
// Add class mappings attributes to configuration object
cfg.AddInputStream(HbmSerializer.Default.Serialize(typeof(Model.Product);
ISessionFactory sessionFactory = cfg.BuildSessionFactory();
For a while, NHMA didn't auto detect classes names because they are now optional in NHibernate (in some scenarios, you would use entity-name instead).
The most recent version however restores the auto-detect behavior with a setting to turn that off if needed.
The attributes must be manually ordered because .NET doesn't guarantee it when compiling (unlike Java).
The end goal of NHMA is to faithfully duplicate the way you write the XML version; so if you have:
<something>
<innerData/>
</something>
The NHMA version will be:
[Something]
[InnerData(2)]
NHMA tries to be smart about deducing certain values (like names), but it will only do so if the value is required.
It also provide helpers like NameType=typeof(XXX) to benefit from intellisense, compile time verification and refactoring.
More details in the documentation:
http://www.nhforge.org/doc/nh/en/index.html#mapping-attributes
If you have not solved your problem yet, try this
[NHibernate.Mapping.Attributes.Class(Table="youtable",NameType=typeof(Contact ))]
public class Contact : DomainClass
{
[NHibernate.Mapping.Attributes.Id(Name = "Id")]
[NHibernate.Mapping.Attributes.Generator(1, Class ="Identity")]
public virtual int ID { get; set; }
[NHibernate.Mapping.Attributes.Property(Name="Name")]
public virtual string Name { get; set; }
[NHibernate.Mapping.Attributes.Property(Name="Town")]
public virtual string Town { get; set; }
}
I'm using like this and it works fine .....
I must say that NHibnerate.Mapping.Atributes component was poorly written.
The code below will lead to a generation of malformed mapping xml
[Class()]
public class Bar{}
Meanwhile, the code below is fine:
[Class(Name="Bar")]
public class Bar{}
Further more, if you place [Generator] attribute after [Id] attribute, then the information about generator will not be included in the xml, but place [Generator] before [Id] will do the jobs.
The 3.0 is under working and I hope that these "nasty" bugs will be fixed.
As indicted above, you have to specify the class' Name since version 2...
I have posted an article on how to work around this by deriving the HbmWriter: http://blog.hopla.org/2009/12/fix-for-nhibernate-mapping-attributes-2-1/
Almost copy of mitjast's answer, with minor fixes and formatting:
[Class(NameType = typeof(DomainClass))]
public class DomainClass
{
[NHibernate.Mapping.Attributes.Generator(Class = "guid")]
[NHibernate.Mapping.Attributes.Id(Name = "DomainID")]
public virtual Guid DomainID { get; set; }
[NHibernate.Mapping.Attributes.Property]
public virtual string Name { get; set; }
}
That definition helped me get through all exceptions and generate valid hbm mapping.
As Mr Cold mentioned, the order of Generator and Id attributes does matter.
But in my case it was discovered that while for one class Id should go first to be actually mentioned within hbm, for another class the first attribute should be Generator. When I change the order of these attributes in one class so that both classes have equal order, the hbm for one of them becomes wrong...
The situation did not change after the release of NHibernate.Mapping.Attributes-for-NHibernate-3.0.0.Alpha2.
Presence of such quirky things looks enough for me to switch to another solution unfortunately...
Related
I am getting an error : i am using entity framework, wcf.
Error:cannot implicitly convert type System.linq.iorderedQueryable<xDataModel.Info> to System.Collection.Generic.List<xServiceLibrary.Info>
Below are my code:
WCF Service:
namespace xServiceLibrary
{
public List<Info> GetScenario()
{
xEntities db = new xEntities();
var query = from qinfo in db.Infoes
select qinfo;
//return query.Cast<Info>().ToList(); (not working)
//return query.toList(); (not working)
return query;
}
}
Interface:
namespace xServiceLibrary
{
[OperationContract]
List<Info> GetScenario();
}
Class:
namespace xServiceLibrary
{
[DataContract]
public class Info
{
[DataMember]
public int Scenario_Id;
[DataMember]
public string Scenario_Name { get; set; }
[DataMember]
public string Company_Name { get; set; }
}
}
update:(2)
I have two class library files.
One is xDataModel namespace in which i have created xmodel.edmx file.
second is xServiceLibrary namespace where i am implementing Wcf Service.
i have attached the xDataModel.dll file in my xServiceLibrary so that i could query my EF Model.
i am not able to understand the concept. any help would be appreciated.
The problem is that you have two different types named Info: DataModel.Info and ServiceLibrary.Info - because these are different types you cannot cast one into the other.
If there is no strong reason for both being there I would eliminate one of them. Otherwise as a workaround you could project DataModel.Info to ServiceLibrary.Info by copying the relevant properties one by one:
var results = (from qinfo in db.Infoes
select new ServiceLibrary.Info()
{
Scenario_Id = qinfo.Scenario_Id,
//and so on
}).ToList();
The problem is that you have two different classes, both called Info, both in scope at the time you run your query. This is a very very bad thing, especially if you thought they were the same class.
If DataModel.Info and ServiceLibrary.Info are the same class, you need to figure out why they are both in scope at the same time and fix that.
If they are different classes, you need to be explicit about which one you are trying to return. Assuming that your EF model includes a set of DataModel.Info objects, your options there are:
Return a List<DataModel.Info> which you can get by calling query.ToList()
Return a List<ServiceLibrary.Info> which you can get by copying the fields from your DataModel.Info objects:
var query = from qinfo in db.Info
select new ServiceLibrary.Info
{
Scenario_Id = q.Scenario_Id,
Scenario_Name = q.Scenario_Name
Company_Name = q.Company_Name
};
Return something else, such as your custom DTO object, similar to #2 but with only the specific fields you need (e.g. if ServiceLibrary.Info is a heavy object you don't want to pass around.
In general, though, your problem is centered around the fact that the compiler is interpreting List<Info> as List<ServiceLibrary.Info> and you probably don't want it to.
Does anybody know if it is possible to control the names of the types generated through Castle DynamicProxy? I was hoping to take advantage of the ability to persist the assembly generated by Castle to add some additional classes with some specific functionality to my project, but I would like to be able to control the names of these generated proxy types. Any help would be greatly appreciated.
I actually plan to persist instances of these classes as well as instances of the original classes that are the sources of the proxies with NHibernate. So, I need these names to be consistent across multiple generations of the assembly.
I did some interesting digging. Specifying proxy names appears to be possible using an INamingScope, but it is far from straightforward to get the INamingScope wedged in. You would need to create your own ProxyFactoryFactory, which would create a ProxyFactory identical to NHibernate.ByteCode.Castle.ProxyFactory, except it would initilize ProxyGenerator:
public class CustomProxyFactory : AbstractProxyFactory {
private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator(new CustomProxyBuilder());
// remainder of code is identical
}
public class CustomProxyBuilder : DefaultProxyBuilder {
public CustomProxyBuilder() : base(new CustomModuleScope()) {}
}
public class CustomModuleScope : ModuleScope {
public CustomModuleScope() : base(false, false, new CustomNamingScope(), DEFAULT_ASSEMBLY_NAME, DEFAULT_FILE_NAME, DEFAULT_ASSEMBLY_NAME, DEFAULT_FILE_NAME) {}
}
public class CustomNamingScope : INamingScope {
public CustomNamingScope() {}
private CustomNamingScope(INamingScope parent) {
ParentScope = parent;
}
public string GetUniqueName(string suggestedName) {
// your naming logic goes here
}
public INamingScope SafeSubScope() {
return new CustomModuleScope(this);
}
public INamingScope ParentScope { get; private set; }
}
I honestly haven't tried running or compiling any of this. Just digging through the NHibernate and Castle.Core source code. Hopefully it gives you some ideas...
Take a look at the ProxyGenerators project in NHContrib. It allows you to pre-generate NHibernate's lazy loading proxies.
http://nhforge.org/wikis/proxygenerators10/default.aspx
Whether you use the ProxyGenerators or not, you integrate your custom proxies into NHibernate via the Proxy Factory Factory. In hibernate.cfg.xml:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="proxyfactory.factory_class">YOUR_PROXY_FACTORY_FACTORY</property>
</session-factory>
</hibernate-configuration>
Take this class as example:
public class Category : PersistentObject<int>
{
public virtual string Title { get; set; }
public virtual string Alias { get; set; }
public virtual Category ParentCategory { get; set; }
public virtual ISet<Category> ChildCategories { get; set; }
public /*virtual*/ void Add(Category child)
{
if (child != null)
{
child.ParentCategory = this;
ChildCategories.Add(child);
}
}
}
When running the application without the virtual keyword of add method, I getting this error:
method Add should be 'public/protected virtual' or 'protected internal virtual'
I understand why properties need to declare as virtual, because thay need to be overridden by the lazy loading feature.
But I don't understand why Methods need to be declare as virtual... they need to be overridden for what reason?
This very confusing!
Methods as well need to be virtual because they could access fields. Consider this situation:
class Entity
{
//...
private int a;
public virtual int A
{
get { return a; }
}
public virtual void Foo()
{
// lazy loading is implemented here by the proxy
// to make the value of a available
if (a > 7)
// ...
}
}
I believe this is required for the lazy-loading feature in NHibernate where NHibernate creates proxies of your entity and controls all access to it. This is why every single method and property must be virtual. Basically, if there is a member doing anything with the entity, NH need to know about it and tap into it.
Like mentioned earlier, in order for NHibernate to do the 'magic' it creates proxy classes which inherit from your entities (Category in your case). However, if you make your entities implement an interface, it will use that interface to create a proxy instead of concrete types. This way, you wouldn't have to mark everything virtual.
EDIT: Some corrections... According to this, i am compelled to say that it almost looks like NH doesn't really do anything with virtual methods, after all. And i even read someone saying that they removed this run-time check from the NH core assembly just to get around it. My assumption would be that it is an older requirements which hasn't been removed. The cool thing is that it looks like there is an initiative to use PostSharp for static proxies, so your classes won't have to declare anything virtual for NH to generate proxies. The bad thing is that it looks like it's been stuck in a branch for almost two years.
I have read in Chapter 4 of the NHibernate docs that all of a persistent classes public methods, properties and events must be declared as virtual.
However, whilst a runtime error is generated for any Properties that are not marked as virtual, I have found that static methods are allowed and do not generate a runtime error . As they are static they are of course not marked virtual which seems to break the rule in point 4.1.4 of the documentation (see above). I have checked the resulting sql and it also implements lazy loading correctly when I run a test against the method so is it therefore ok to use static methods?
Here's the basic details of the persistant class:
public class CmsPage
{
public virtual int? Id { get; set; }
public virtual string Title { get; set; }
public virtual void Update()
{
using (ISession session = NHibernateHelper.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
session.Update(this);
transaction.Commit();
}
}
}
// Note: static and non-virtual and yet it will not cause a problem for Nhibernate
public static IEnumerable<CmsPage> GetList()
{
IList<CmsPage> pageList;
using (ISession session = NHibernateHelper.OpenSession())
{
string hql = "from CmsPage p";
pageList = session.CreateQuery(hql)
.List<CmsPage>();
}
return pageList;
}
}
So my question is why is it ok to use a static method in the persistent domain class when the documentation seems to say it's not?
Please answer from NHibernate's point of view not an OO design point of view; I don't want to get into an OOD/OOP debate if it can be avoided please.
The documentation says: "NHibernate works best if these classes follow some simple rules, ..." It doesn't say it won't work (clearly it does work).
So, really, the discussion boils down to an OO issue.
Actually this applies only to properties. Methods are not persisted, so proxies and lazy-loading does not apply. Ideally you should separate data access (the static methods in your case) from the domain object. But you are correct to point this out, maybe the documentation should have been clearer.
In conclusion your class is perfectly fine but it could be even better if you separated the concerns.
NHibernate needs all your properties to be virtual because it carries out its lazy-loading magic by making proxies of your objects that override everything. So when you write this code:
class Foo {
public virtual Foo[] Neighbors { get; set; }
}
NHibernate secretly generates classes like:
class NHProxy03450843275 : Foo {
public virtual Foo[] Neighbors { /* Godawful lazy-loading magic goes here */ }
}
Actually it's worse than that, but this gives you the idea. Anyway, static methods aren't bound to particular instances of a class, so NH doesn't need proxies to deal with them. Thus they can be non-virtual.
An advantage of an IoC container is that you can swap in a mock service at the bottom of your object graph. However this seems much harder to do in Spring.Net than in other IoC Containers. Here's some code that does it in Unity and has Spring.Net code;
namespace IocSpringDemo
{
using Microsoft.Practices.Unity;
using NUnit.Framework;
using Spring.Context;
using Spring.Context.Support;
public interface ISomeService
{
string DoSomething();
}
public class ServiceImplementationA : ISomeService
{
public string DoSomething()
{
return "Hello A";
}
}
public class ServiceImplementationB : ISomeService
{
public string DoSomething()
{
return "Hello B";
}
}
public class RootObject
{
public ISomeService SomeService { get; private set; }
public RootObject(ISomeService service)
{
SomeService = service;
}
}
[TestFixture]
public class UnityAndSpringDemo
{
[Test]
public void UnityResolveA()
{
UnityContainer container = new UnityContainer();
container.RegisterType<ISomeService, ServiceImplementationA>();
RootObject rootObject = container.Resolve<RootObject>();
Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
}
[Test]
public void UnityResolveB()
{
UnityContainer container = new UnityContainer();
container.RegisterType<ISomeService, ServiceImplementationB>();
RootObject rootObject = container.Resolve<RootObject>();
Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
}
[Test]
public void SpringResolveA()
{
IApplicationContext container = ContextRegistry.GetContext();
RootObject rootObject = (RootObject)container.GetObject("RootObject");
Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
}
[Test]
public void SpringResolveB()
{
// does not work - what to do to make this pass?
IApplicationContext container = ContextRegistry.GetContext();
RootObject rootObject = (RootObject)container.GetObject("RootObject");
Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
}
}
}
For the benefit of Spring, the following needed to be in the App.config file. Clearly this only serves the first spring test, and not the second. Can you put multiple spring configurations in the config file? If so, what is the syntax and how do you access them? Or is there another way to do this?
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context>
<resource uri="config://spring/objects"/>
</context>
<objects xmlns="http://www.springframework.net">
<object name="RootObject" type="IocSpringDemo.RootObject, IocDemo" autowire="constructor" />
<object name="service" type="IocSpringDemo.ServiceImplementationA, IocDemo" autowire="constructor" />
</objects>
</spring>
Update
Here is a partial answer based at code at the links that Marko Lahma gave to Mark Pollack's blog. I have the above tests passing, with the following code:
public static class SpringHelper
{
public static T Resolve<T>(this IApplicationContext context, string name)
{
return (T)context.GetObject(name);
}
public static void RegisterType<T>(this GenericApplicationContext context, string name)
{
context.RegisterType(name, typeof(T));
}
public static void RegisterType(this GenericApplicationContext context, string name, Type type)
{
IObjectDefinitionFactory objectDefinitionFactory = new DefaultObjectDefinitionFactory();
ObjectDefinitionBuilder builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, type);
builder.SetAutowireMode(AutoWiringMode.AutoDetect);
context.RegisterObjectDefinition(name, builder.ObjectDefinition);
}
}
...
[Test]
public void SpringResolveA()
{
GenericApplicationContext container = new GenericApplicationContext();
container.RegisterType<RootObject>("RootObject");
container.RegisterType<ServiceImplementationA>("service");
RootObject rootObject = container.Resolve<RootObject>("RootObject");
Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
}
[Test]
public void SpringResolveB()
{
GenericApplicationContext container = new GenericApplicationContext();
container.RegisterType<RootObject>("RootObject");
container.RegisterType<ServiceImplementationB>("service");
RootObject rootObject = container.Resolve<RootObject>("RootObject");
Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
}
This raises a few questions to me:
I want to integrate this technique into existing code that uses the usual container. Why do I have to use a different container type, GenericApplicationContext in this case? What if I want to read data into this object from the existing spring config in app.config or web.config? Would it work as the usual context? Could I then write data over these registrations with code?
How can I specify that ISomeService is to be created as a singleton? I don't mean supply a singleton instance to the container, but the container to create the instance, resolving its constructor, and use it when that type is needed.
how can I do the equivalent of container.RegisterType<ISomeService, ServiceImplementationA>(); ? I want to register type mappings to use in all cases where that type is needed by a constructor.
What exactly does container.RegisterType<ServiceImplementationA>("service"); do? It seems to register ServiceImplementationA as the implementation of ISomeService but ISomeServiceis never mentioned, so there could be ambiguity. e.g. what if ServiceImplementationA implemented more than one interface.
What is the string name given to the registration for? It won't work with en empty string, but it doesn't seem to matter what it is.
Am I trying to use spring in a way that it just does not work? I'm trying to use it like other IoC containers, but it's not quite working.
Adding as new answer trying to address the open points...
I want to integrate this technique
into existing code that uses the usual
container. Why do I have to use a
different container type,
GenericApplicationContext in this
case? What if I want to read data into
this object from the existing spring
config in app.config or web.config?
Would it work as the usual context?
Could I then write data over these
registrations with code?
Spring has concrete application context implementations for different kind of initialization tactics. The most common ones to use are GenericApplicationContext (manual), XmlApplicationContext (XML files) and WebApplicationContext (very much like XmlApplicationContext but tailored for web use). They all implement common interface: IApplicationContext which is the preferred way to access these containers.
Unfortonately altering registrations with code usually means that you need to use the specific sub-class directly. With GenericApplicationContext and StaticApplicationContext this is quite natural but XmlApplicationContext is usually considered to be XML only and this ways "fixed" to XML definition.
How can I specify that ISomeService is
to be created as a singleton? I don't
mean supply a singleton instance to
the container, but the container to
create the instance, resolving its
constructor, and use it when that type
is needed.
Your SpringHelper does just that, by default all objects in Spring are singletons. You could alter this behavior by calling ObjectDefinitionBuilder's SetSingleton method with false.
how can I do the equivalent of
container.RegisterType(); ? I want to
register type mappings to use in all
cases where that type is needed by a
constructor.
Spring uses object names (ids) to distinct between different implementations. So if you want to get specific type to serve a specific instance in case that there are many alternatives you should refer to this specific instance by name. If you are using autowiring and your object has dependency to interface ISomeService and there's only one object registered that implements it, the autowiring can set it without ambiguity.
What exactly does
container.RegisterType("service");
do? It seems to register
ServiceImplementationA as the
implementation of ISomeService but
ISomeServiceis never mentioned, so
there could be ambiguity. e.g. what if
ServiceImplementationA implemented
more than one interface.
Continuing from previous answer, this registers singleton of type ServiceImplementationA with name "service". This object comes autowiring candidate with all it's implemented interfaces (and with it's concrete type of course).
What is the string name given to the
registration for? It won't work with
en empty string, but it doesn't seem
to matter what it is.
It matters a great deal as explained earlier. The name is unique id within that context (parent context could have object with same name) and can be used to access specific object registrations. In short where other frameworks may associate a type as key to object registration, Spring uses name.
That's a bit apples and oranges comparison as the unit test uses code configuration for Unity and XML (app.config) configuration for Spring.NET.
If you go the XML route, then you can either comment out old implementation A and define the B implementation as the one to use - that what's configuration is all about right? Other option is to have dedicated XML files for each scenario (configuration setup) and include them via context's resource definitions (you have inline resource now). Other options include file system and assembly, see the web configuration section in Spring.NET's manual for a nice example.
If you go the code configuration route I would suggest to check Spring.NET Recoil and upcoming CodeConfig.