NHibernate Mapping Property Which Depends on Another Property - nhibernate

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; }
}
}

Related

"Nullable object must have a value" when Mapping bool? to bool?

In my app, I fetch two attributes IsLoopCar and LoopStatusSet from a DB and Store them to a model class:
private static ChecklistModel MapChecklistModel(DataRow row)
{
var checklist = new ChecklistModel
{
IsLoopCar = Convert.IsDBNull(row["IsLoopCar"]) ? null : Convert.ToBoolean(row["IsLoopCar"]),
LoopStatusSet = Convert.IsDBNull(row["LoopStatusSet"]) ? null : Convert.ToBoolean(row["LoopStatusSet"])
}
}
In my model class and the viewModel I map my model class to, the data type of these two attributes is bool?
public class ChecklistModel
{
public bool? IsLoopCar { get; set; }
public bool? LoopStatusSet { get; set; }
}
public class GetPaymentInformationViewModel
{
public bool? IsLoopCar { get; set; }
public bool? LoopStatusSet { get; set; }
}
The value of the attribute in my DB is null. When I map the model to the viewmodel using AutoMapper (7.0.1), I get an error message which I don't understand:
GetPaymentInformationViewModel gpivm = _mapper.Map<ChecklistModel, GetPaymentInformationViewModel>(checklist);
The mapping configuration is very basic:
CreateMap<ChecklistModel, GetPaymentInformationViewModel>();
The error message is:
InvalidOperationException: Nullable object must have a value.
I don't understand what's the point in mapping nullable bools, when they have to have a value. I need to have this value to be null when i pass it to the view because it works as kind of a checkpoint where the user must select a yes/no value with no initial default value set.
Based on the recommendation of Lucian, I tried to reproduce the problem with a fresh console app but it didn't fail there. As it turned out, the problem was in my view model where I had written a custom setter that makes no sense:
[Required]
[Display(Name = "IsLoopCar")]
public bool? IsLoopCar
{
get
{
return _IsLoopCar;
}
set
{
if (value.Value == true)
_IsLoopCar = value.Value;
else
{
_IsLoopCar = value.Value;
LoopStatusSet = null;
}
}
}
The field value.Value cannot be read because it does not exists. It's supposed to be like that:
[Required]
[Display(Name = "IsLoopCar")]
public bool? IsLoopCar
{
get
{
return _IsLoopCar;
}
set
{
if (value == true)
_IsLoopCar = value;
else
{
_IsLoopCar = value;
LoopStatusSet = null;
}
}
}

How to resolve an error with WCF data contract -Message = "There was an error while trying to serialize parameter

I have two data contracts of same contents in two different namespaces. i have copied one datacontract to another and
passed to a particular method. but it is giving the below error and throwing exception. it is not going into that method.
Please let me know any ideas /suggestions on how to resolve this.Appreciate your help:
Exception errror:
{"Type 'System.Collections.Generic.List`1[[GlobalWcfServiceLib.TopicDetailsInfo, GlobalWcfContracts, Version=1.2.2.0, Culture=neutral,
PublicKeyToken=17c64733a9775004]]' with data contract name 'ArrayOfTopicDetailsInfo:http://CName.GlobalService/11.1/2010/11'
is not expected. Consider using a DataContractResolver or add any types not known statically to the list of
known types - for example, by using the KnownTypeAttribute attribute or by
adding them to the list of known types passed to DataContractSerializer."}
Message = "There was an error while trying to serialize parameter
http://CName.SharedServices.DBServiceLib:subscriptionDataContract.
The InnerException message was 'Type 'System.Collections.Generic.List`1
[[GlobalWcfServiceLib.TopicDetailsInfo,
GlobalWcfContra...
//////
Here is my scenario : i am copying the data from dc to new data contract as below. after copying , when i am executing the createsubscriptions method i am getting the above mentioned error. i have given the details of data contract and error attached to this question. please refer to that as well.
Method1(SubscriptionDataContracts dc)
{
SubscriptionDataContract subscriptionDataContract = new SubscriptionDataContract();
List<SubscriptionTopicInfo> topicsInfo = dc.TopicList;
List<SubscriptionTopic> newTopicsList = new List<SubscriptionTopic>();
subscriptionDataContract.ExtensionData = dc.ExtensionData;
subscriptionDataContract.UserID = dc.UserID;
for (int i = 0; i < topicsInfo.Count; i++)
{
SubscriptionTopic topic = new SubscriptionTopic();
topic.DBHandle = topicsInfo[i].DBHandle;
topic.Topic = topicsInfo[i].Topic;
topic.Target = topicsInfo[i].Target;
newTopicsList.Add(topic);
}
subscriptionDataContract.TopicList = newTopicsList;
CreateSubscriptions(subscriptionDataContract); //getting the above mentioned error in another dll after going into this method
}
////////////////////////////////
//My data contract
[DataContract(Name = "TopicDetailsInfo", Namespace = "http://CName.GlobalService")]
[Serializable]
public class TopicDetailsInfo
{
protected object topic;
protected object baseObjectType;
[DataMember]
public object BaseObjectType
{
get
{
return baseObjectType;
}
set
{
baseObjectType = value;
}
}
[DataMember]
public object TopicID
{
get
{
return topic;
}
set
{
topic = value;
}
}
static public TopicDetailsInfo CreateTopic<T, mT>(IComparable<T> objectType, IComparable<mT> objectID)
{
var topicDetails = new TopicDetailsInfo();
topicDetails.BaseObjectType = objectType;
topicDetails.TopicID = objectID;
return topicDetails;
}
}
[DataContract(Name = "SubscriptionTopicInfo", Namespace = "http://CName.GlobalService")]
[KnownType(typeof(List<TopicDetailsInfo>))]
[Serializable]
public class SubscriptionTopicInfo
{
private object topic;
private object target;
private object creator;
[DataMember]
public object Topic
{
get
{
return topic;
}
set
{
topic = value;
}
}
[DataMember]
public object Target
{
get
{
return target;
}
set
{
target = value;
}
}
[DataMember]
public object DBHandle
{
get
{
return creator;
}
set
{
creator = value;
}
}
static public SubscriptionTopicInfo CreateSubscriptions<T, mT, nT>(IList<TopicDetailsInfo> topic, IComparable<mT> target, IComparable<nT> handle)
{
var subscriptionTopic = new SubscriptionTopicInfo();
subscriptionTopic.Target = target;
subscriptionTopic.Topic = topic;
subscriptionTopic.DBHandle = handle;
return subscriptionTopic;
}
}
[DataContract(Name = "SubscriptionData", Namespace = "http://CName.GlobalService")]
[KnownType(typeof(List<SubscriptionTopicInfo>))]
[Serializable]
public class SubscriptionDataContracts : IExtensibleDataObject
{
private ExtensionDataObject extensionDataObjectValue;
[DataMember]
public string UserID
{
get;
set;
}
[DataMember]
public string ProjectID
{
get;
set;
}
[DataMember]
public string FromDiscipline
{
get;
set;
}
[DataMember]
public string ModuleID
{
get;
set;
}
[DataMember]
public string SessionID
{
get;
set;
}
[DataMember]
public List<SubscriptionTopicInfo> TopicList
{
get;
set;
}
public ExtensionDataObject ExtensionData
{
get
{
return extensionDataObjectValue;
}
set
{
extensionDataObjectValue = value;
}
}
}

NHibernate - IUserType For Changing Type?

My application has the following classes:
public class Widget {
public virtual int Id { get; set; }
public virtual WidgetType Type { get; set; }
public virtual string Parameters { get; set; }
}
public class WidgetType {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string ParametersAssembly { get; set; }
public virtual string ParametersClass { get; set; }
}
Now if i'd like to update the Parameters for a particular widget i would say something like:
// Get the widget
var widget = GetWidget(1);
// Create an instance of the type parameters class
var parameters = Activator.CreateInstance(Assembly.LoadFrom(Server.MapPath("~/bin/"
+ widget.Type.ParametersAssembly + ".dll")).GetType(widget.Type.ParametersClass));
... Code here to update the parameters
widget.Parameters = new XmlSerializer(parameters.GetType()).Serialize(parameters);
I have to do the reverse when i wish to get the parameters. You can imagine this becomes quite tedious. I was wondering if it was possibly to automatically do this?
I've been looking at the IUserType interface. I found an article which is kind of similar. However my problem is a little more complicated as my type changes based on the type of the widget.
I'd appreciate it if someone could let me know if this is possible and possibly how it could be achieved. Thanks
an easy way
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;
// code to deserialize the Parameters and set to Parameters
var ptype = Assembly.LoadFrom(Server.MapPath("~/bin/" + widget.Type.ParametersAssembly + ".dll")).GetType(widget.Type.ParametersClass);
Parameters = Activator.CreateInstance(ptype);
}
}
private object _parameters;
public virtual object Parameters
{
get
{
if (_parameters == null)
_parameters = Activator.CreateInstance(Assembly.LoadFrom(Server.MapPath("~/bin/" + widget.Type.ParametersAssembly + ".dll")).GetType(widget.Type.ParametersClass));
return _parameters;
}
set { _parameters = value; }
}
}
it can't be in the Parameters property because then you have to get -> alter -> set instead of get -> alter. But you are right that building the parameters object should go in the getter of Parameters because only there we can be sure to have the WidgetType loaded
it is essentially the same as a UserType except that we know that WidgetType is there

JSON.Net - DeserializeObject Format

I'm using JSON.Net to try and deserialize some survey responses from SurveyGizmo.
Here's a snapshot of the data I'm reading in:
{"result_ok":true,
"total_count":"44",
"page":1,
"total_pages":1,
"results_per_page":50,
"data":[
{"id":"1",
"contact_id":"",
"status":"Complete",
"is_test_data":"0",
"datesubmitted":"2011-11-13 22:26:53",
"[question(59)]":"11\/12\/2011",
"[question(60)]":"06:15 pm",
"[question(62)]":"72",
"[question(63)]":"One",
"[question(69), option(10196)]":"10",
I've setup a class as far as datesubmitted but I'm not sure how to setup the class to deserialize the questions given that the amount of questions will change? I also need to capture the option if it's present.
I'm using this code to use the JSON.NET Deserialize function:
Dim responses As Responses = JsonConvert.DeserializeObject(Of Responses)(fcontents)
Classes:
Public Class Responses
Public Property result_OK As Boolean
Public Property total_count As Integer
Public Property page As Integer
Public Property total_pages As Integer
Public Property results_per_page As Integer
Public Overridable Property data As List(Of surveyresponse)
End Class
Public Class SurveyResponse
Public Property id As Integer
Public Property status As String
Public Property datesubmitted As Date
End Class
This trick to support totally crazy mappings is to use JsonConverter and completely replace the parsing for that object, (I apologize for the C#, but I'm no good at VB syntax):
class Program
{
static void Main(string[] args)
{
var result = JsonConvert.DeserializeObject<Responses>(TestData);
}
const string TestData = #"{""result_ok"":true,
""total_count"":""44"",
""page"":1,
""total_pages"":1,
""results_per_page"":50,
""data"":[
{""id"":""1"",
""contact_id"":"""",
""status"":""Complete"",
""is_test_data"":""0"",
""datesubmitted"":""2011-11-13 22:26:53"",
""[question(59)]"":""11\/12\/2011"",
""[question(60)]"":""06:15 pm"",
""[question(62)]"":""72"",
""[question(63)]"":""One"",
""[question(69), option(10196)]"":""10"",
}]}";
}
[JsonObject]
class Responses
{
public bool result_ok { get; set; }
public string total_count { get; set; }
public int page { get; set; }
public int total_pages { get; set; }
public int results_per_page { get; set; }
public SurveyResponse[] Data { get; set; }
}
[JsonObject]
// Here is the magic: When you see this type, use this class to read it.
// If you want, you can also define the JsonConverter by adding it to
// a JsonSerializer, and parsing with that.
[JsonConverter(typeof(DataItemConverter))]
class SurveyResponse
{
public string id { get; set; }
public string contact_id { get; set; }
public string status { get; set; }
public string is_test_data { get; set; }
public DateTime datesubmitted { get; set; }
public Dictionary<int, string> questions { get; set; }
}
class DataItemConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SurveyResponse);
}
public override bool CanRead
{
get { return true; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var value = (SurveyResponse)existingValue;
if (value == null)
{
value = new SurveyResponse();
value.questions = new Dictionary<int, string>()
}
// Skip opening {
reader.Read();
while (reader.TokenType == JsonToken.PropertyName)
{
var name = reader.Value.ToString();
reader.Read();
// Here is where you do your magic
if (name.StartsWith("[question("))
{
int index = int.Parse(name.Substring(10, name.IndexOf(')') - 10));
value.questions[index] = serializer.Deserialize<string>(reader);
}
else
{
var property = typeof(SurveyResponse).GetProperty(name);
property.SetValue(value, serializer.Deserialize(reader, property.PropertyType), null);
}
// Skip the , or } if we are at the end
reader.Read();
}
return value;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Now obviously there's a lot more you would want to do to get this really robust, but this gives you the basics of how to do it. There are more lightweight alternatives if you simply need to change property names (either JsonPropertyAttribute or overriding DefaultContractResolver.ResolvePropertyName(), but this gives you full control.

Can I use NHibernate to store an object in xml serialized form?

Say I have a class like this:
public class MyClass
{
public int Id { get; set; }
public DateTime Date { get; set; }
public string String1 { get; set; }
public string String2 { get; set; }
public string String3 { get; set; }
public string String4 { get; set; }
}
Is it possible to get NHibernate to store it in the following schema?
CREATE TABLE [dbo].[MyClass](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Xml] [varchar](max) NOT NULL,
)
Where the Id maps to Id, but then all other fields get serialized into XML (or otherwise)? I don't mind if these other fields have to go on a child object like the below, if that helps:
public class MyClass
{
public int Id { get; set; }
public AllOtherOptions Options { get; set; }
}
public class AllOtherOptions
{
public DateTime Date { get; set; }
public string String1 { get; set; }
public string String2 { get; set; }
public string String3 { get; set; }
public string String4 { get; set; }
}
I am thinking about doing something similar for an upcoming project. The project requires collecting a lot of data but only a few elements need to be stored in a relational database. I haven't started experimenting but these are my thoughts so far.
You can map an XML data type by creating a type that implements IUserType. If the child class (AllOtherOptions) is serializable, you should be able to map the XML field as a private member in MyClass and serialize/deserialize AllOtherOptions as needed. You could either dynamically maintain the XML field (sounds like a lot of work) or create an interceptor to do it. My thinking is that MyClass would implement an interface such as
public interface IXmlObjectContainer
{
void SerializeChildObjects();
void DeSerializeChildObjects();
}
and the interceptor would call those methods as needed. That's a proof of concept idea. I would probably refine that by exposing pairs of xml fields and serializable objects to remove the work of serializing from IXmlObjectContainer implementers. Or maybe handle serialization through the XML field's get/set accessors.
More info:
Working with XML Fields in NHibernate
Another XML implementation of IUserType
I had the same idea to save object in XML column. My idea was other. I took code from links and changed it to generic IUserType implementation. So any field/prop which is [Serializable] can be saved in XML column.
public class XmlUserType<T> : IUserType where T : class
{
public new bool Equals(object x, object y)
{
return x == y;
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
if (names.Length != 1)
throw new InvalidOperationException("names array has more than one element. can't handle this!");
var val = rs[names[0]] as string;
if (string.IsNullOrWhiteSpace(val) == false)
{
return KRD.Common.GenericXmlSerialization.Deserialize<T>(val);
}
return null;
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
var parameter = (DbParameter)cmd.Parameters[index];
T toSave = value as T;
if (toSave != null)
{
parameter.Value = KRD.Common.GenericXmlSerialization.Serialize(toSave);
}
else
{
parameter.Value = DBNull.Value;
}
}
public object DeepCopy(object value)
{
T toCopy = value as T;
if (toCopy == null)
return null;
string serialized = KRD.Common.GenericXmlSerialization.Serialize(toCopy);
return KRD.Common.GenericXmlSerialization.Deserialize<T>(serialized);
}
public object Replace(object original, object target, object owner)
{
throw new NotImplementedException();
}
public object Assemble(object cached, object owner)
{
var str = cached as string;
if (string.IsNullOrWhiteSpace(str) == false)
{
return null;
}
return KRD.Common.GenericXmlSerialization.Deserialize<T>(str);
}
public object Disassemble(object value)
{
var toCache = value as T;
if (toCache != null)
{
return KRD.Common.GenericXmlSerialization.Serialize(toCache);
}
return null;
}
public SqlType[] SqlTypes
{
get
{
return new SqlType[] { new SqlXmlType() };
}
}
public Type ReturnedType
{
get { return typeof(XmlDocument); }
}
public bool IsMutable
{
get { return true; }
}
}
public class SqlXmlType : SqlType
{
public SqlXmlType()
: base(DbType.Xml)
{
}
}
Usage with FluentNHibernate:
public class MainObject
{
public int Id { get; set; }
public ObjectAsXml Data { get; set; }
}
public class ObjectAsXml
{
public string Name { get; set; }
public int Date { get; set; }
public ObjectAsXml OtherObject { get; set; }
}
private class MainObjectMap : ClassMap<MainObject>
{
public MainObjectMap()
{
Id(id => id.Id);
Map(m => m.Data).CustomType<XmlUserType<ObjectAsXml>>().Nullable();
}
}
Maybe it will help somebody.