Using IList in Nhibernate, does not get initialized - nhibernate

I basically have:
Public Class Job: MyBaseClass
{
public virtual string JobInformation {get;set;}
...
public virtual List<Item> JobItems {get;set;}
}
I was using a List and initializing it (JobItems = new List();) in the constructor. However, I was getting an Exception (Nhibernate.Collection.Generic.PersistentGenericBag)
I read this question and it said I should use IList instead.
So now I have
public class Job: MyBaseClass
{
public virtual string JobInformation {get;set;}
...
public virtual IList<Item> JobItems {get;set;}
}
public virtual void AddItem(Item item)
{
//snip validation
this.JobItems.Add(item);
}
However, it throws a NullReferenceException because JobItems isn't initialized yet. When does NHibernate initialize this collection? Or how can I solve this issue?

use a backing field and on return make sure it isn't null
public IList<Item> JobItems
{
get { return _jobItems ?? (_jobItems = new List<Item>()); }
set { _jobItems = value; }
}

You should initialize the collection if it hasn't been previously initialized.
private IList<Item> _jobItems;
public IList<Item> JobItems
{
get
{
return _jobItems ?? (_jobItems = new List<Item>());
}
private set
{
_jobItems = value;
}
}

Related

How to map object type field in Nhibernate Auto Mapping

When trying to map, I got this error:
Association references unmapped class: System.Object
My class:
public partial class MessageIdentifier
{
public virtual int ID { get; set; }
public virtual object Item { get; set; }
}
And the convention:
public class MyUsertypeConvention : IPropertyConvention
{
public void Apply(IPropertyInstance instance)
{
if (instance.Type.Name == "Object")
instance.CustomType<string>();
}
}
Kindly suggest how to map?
As a simple (quick, naive) solution - I would suggest to create and map real string property. And then let your setter and getter (or some AOP or listener) to do the "to/from string conversion":
public partial class MessageIdentifier
{
public virtual int ID { get; set; }
public virtual object Item
{
get { return ... my conversion from string; }
set { ItemString = ...my conversion to string; }
}
public virtual string ItemString { get; set; }
}
A smart and preferred (but a bit more challenging) is to create CustomType - which will hide that conversion and support REUSE. Check e.g. here
NHibernate Pitfalls: Custom Types and Detecting Changes
Creating and Testing a Custom NHibernate User Type
Not a satisfactory answer. It doesn't work with class that is generated from xsd by using XML. You can try the following:
public partial class MessageIdentifier
{
public virtual int ID { get; set; }
private object itemField;
public object Item
{
get { return this.itemField; }
set { this.itemField = value; }
}
}

RavenDb and protecting the collection in a document/entity

Hi I'm used to have the following entity
public class Foo
{
private IList<Bar> _bars;
public IEnumerable<Bar> Bars { get { return bars; } }
public void Add(Bar bar)
{
/* Validation logic here */
_bars.Add(bar);
}
}
I'm suspecting this won't work with RavenDb or am I'm wrong?
Can I keep my collection with Bars protected from outside manipulating (in other words not allowing foo.Bars.Add(bar);)
I found the solution to use two properties.
public IEnumerable Bars { get { return InnerBars; } }
private List InnerBars { get; set; }}
A private setter on an automatic property is the easiest and most readable way without doing anything special.
public class Foo
{
public IEnumerable<Bar> Bars { get; private set; }
public void Add(Bar bar)
{
Bars.Add(bar);
}
}
Another way would be with attributes:
// pick one or the other
using Newtonsoft.Json // on 1.0
using Raven.Imports.Newtonsoft.Json // on 2.0
...
public class Foo
{
[JsonProperty(PropertyName = "Bars")]
private IList<Bar> _bars;
[JsonIgnore]
public IEnumerable<Bar> Bars { get { return bars; } }
public void Add(Bar bar)
{
_bars.Add(bar);
}
}

NHibernate Mapping Property Which Depends on Another Property

I have the following class:
public class Widget {
public virtual int Id { get; set; }
[Required]
public virtual WidgetType Type { get; set; }
public virtual string SerializedParameters {
get {
return new XmlSerializer(Parameters.GetType()).Serialize(Parameters);
} set {
Parameters = new XmlSerializer(Assembly
.LoadFrom(Server.MapPath(Type.ModelAssembly))
.GetType(Type.ModelClass)
).Deserialize(value);
}
}
private object _parameters;
public virtual object Parameters {
get {
if (_parameters == null)
_parameters = Activator.CreateInstance(Assembly
.LoadFrom(Server.MapPath(Type.ModelAssembly))
.GetType(Type.ModelClass)
);
return _parameters;
} set { _parameters = value; }
}
}
The Parameters property is not mapped to the database but the SerializedParameters property is. However when it tries to get the information from the database and set the SerializedParameters (which subsequently sets the Parameters) the Type property is null and therefore an exception is thrown. I guess this depends on the order in which NHibernate sets the properties for the Widget but i can't get it to work.
I was wondering if there was a way around this. Appreciate the help. Thanks
moved the deserialization in the getter from the setter because as you said the type is not there yet
public class Widget
{
public virtual int Id { get; set; }
public virtual WidgetType Type { get; set; }
private string _serializedParameters;
private virtual string SerializedParameters {
get
{
return new XmlSerializer(Parameters.GetType()).Serialize(Parameters);
}
set
{
_serializedParameters = value;
}
}
private object _parameters;
public virtual object Parameters
{
get
{
if (_parameters == null)
{
if (!string.IsNullOrEmpty(serializedParameters))
{
// code to deserialize the Parameters and set to Parameters
_parameters = new XmlSerializer(Assembly
.LoadFrom(Server.MapPath(Type.ModelAssembly))
.GetType(Type.ModelClass)
).Deserialize(value);
}
else
{
// no existing parameters, then create new object
_parameters = Activator.CreateInstance(Assembly.LoadFrom(Server.MapPath("~/bin/" + widget.Type.ParametersAssembly + ".dll")).GetType(widget.Type.ParametersClass));
}
}
return _parameters;
}
set { _parameters = value; }
}
}

WCF possibly serialization related issue

On server I have the following class
public class A
{
string a1 {get; set ;}
string a2 {get; set;}
}
I have defined a service with the following operation contract
[OperationContract]
public list<A> GetAll()
{
return new List<A> {new A {a1="1", a2="2"}, new A{a1="3", a2="4"}};
}
in the reference there is defined a shallow copy of A in the following way
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="GetAll", Namespace="http://schemas.datacontract.org/2004/07/SomeModel")]
[System.SerializableAttribute()]
public partial class A: object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string A1Field;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string A2Field;
[global::System.ComponentModel.BrowsableAttribute(false)]
public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
get {
return this.extensionDataField;
}
set {
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string A1{
get {
return this.A1Field;
}
set {
if ((object.ReferenceEquals(this.A1Field, value) != true)) {
this.A1Field= value;
this.RaisePropertyChanged("A1");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string A2{
get {
return this.A2Field;
}
set {
if ((object.ReferenceEquals(this.A2Field, value) != true)) {
this.A2Field= value;
this.RaisePropertyChanged("A2");
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName) {
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null)) {
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
On the client I call the service.GetAll() and I use the shallow copy of A, defined in the proxy which defines my model for a view. the call is something similar to
ActionResult GetAll()
{
List<A> allAs = service.GetAll();
return new View (allAs);
}
However the list on the client is always emtpy. What is the problem?
You should define your data class, A as a datacontract:
[DataContract]
public class A
{
[DataMember]
public string a1 {get; set ;}
[DataMember]
public string a2 {get; set ;}
}
On the class you will need DataContract attribute from System.Runtime.Serialization.DataContractAttribute namespace.
Some thing like this
[DataContract]
public class A
{
[DataMember]
public string a1 {get; set ;} //This should be public
[DataMember]
public string a2 {get; set;}//This should be public
}
Read more on MSDN

Fluent NHibrnate - Virtual calls in constructor -Best Practice

I have an entity declared similar to this:
public class Comment
{
public Comment(string text, DateTime creationDate, string authorEmail)
{
Text = text;
CreationDate = creationDate;
AuthorEmail = authorEmail;
}
public virtual string Text { get; private set; }
public virtual DateTime CreationDate { get; set; }
public virtual string AuthorEmail { get; private set; }
}
I have taken it from Is it OK to call virtual properties from the constructor of a NHibernate entity?
I get warning as 'Virtual Calls in constructor'.
Though, it doesn't pose any practical issue because virtual members are declared solely for NH to proxy. However, I was wondering if I should move the constructor method to a new factory class with new method being declared as
CreateComment(string text, DateTime creationDate, string authorEmail)
What will be the best practice in this case?
Please note that currently I have 4-5 overloaded constructors in my domain entity. Above is just an example.
Thank you!
I have tested with FluentNHibernate, you can do it like this:
public class Comment
{
private string _text;
private DateTime _creationDate;
private string _authorEmail;
public Comment(string text, DateTime creationDate, string authorEmail)
{
_text = text;
_creationDate = creationDate;
_authorEmail = authorEmail;
}
public virtual string Text
{
get { return _text; }
private set { _text = value; }
}
public virtual DateTime CreationDate
{
get { return _creationDate; }
set { _creationDate = value; }
}
public virtual string AuthorEmail
{
get { return _authorEmail; }
private set { _authorEmail = value; }
}
}
I prefer having a parameterless (default) constructor and constructing like so:
var comment = new Comment {
Text = "Something offensive and political.",
CreationDate = DateTime.Now,
AuthorEmail = "someonestupidwithanopinion17#aol.com"
};
Now the issue doesn't matter.
If your properties are only virtual to accomodate nHibernate, you can just make them encapsulate concrete fields (nhibernate knows how to cope with that: see here (default-access) and here (access).
it's supported in fluent nh as well.