Updating Fluent nHibernate causes problems with missing property - nhibernate

I am trying to update the nHibernate version in my application.
I used nuGet and updated NHibernate v2.1.2.4000 to v3.3.2.4000
And fluent NHibernate from v1.1.0.685 to v1.3.0.733
I was expecting a few issues but the error I'm getting is odd and I can't quite figure it out.
In my "many to many" convention there is this line:
var userDefined = instance.Relationship.Columns.UserDefined.FirstOrDefault();
if (userDefined != null)
{
instance.Relationship.Column(userDefined.EntityType.Name + "Id");
}
The problem is that after the update of the DLLs the "UserDefined" property no longer exists. What I can't understand is whether I need to redefine it somewhere, or whether there's a different way of accessing that property.
I was under the impression that the "UserDefined" property was part of fluent nHibernate.
Does anyone know how to get this one working?
Many thanks

FluentNHibernate refactored the way it represents specified values.
Before there was one value and indicators who set them (default, convention, explicit). Now there are values for all three kinds and when reading it uses something like explicit ?? convention ?? default hence the tests for explicit/user defined values are no longer needed.
Remove all lines but instance.Relationship.Column(userDefined.EntityType.Name + "Id");

Related

Using the DoctrineObjectConstructor, how are new entities created?

I am attempting to use JMSSerializerBundle to consume JSON into Doctrine entities. I need to both create new entities where they do not already exist in the database, and update existing entities when they do already exist. I am using the DoctrineObjectConstructor included in the JMSSerializer package to help with this. When I consume JSON which contains a property designated as an identifier, such as:
{
"id": 1,
"some_other_attribute": "stuff"
}
by attempting to deserialize it, JMSSerializer causes warnings and eventually dies with an exception for attempting to utilize reflection to set properties on a null value. The warnings all look like this:
PHP Warning: ReflectionProperty::setValue() expects parameter 1 to be object, null given in /Users/cdonadeo/Repos/Ubertester/vendor/jms/serializer/src/JMS/Serializer/GenericDeserializationVisitor.php on line 176
If I manually insert an entity with ID 1 in my database and make another attempt then I receive no errors and everything appears to be working correctly, but I'm now short half my functionality. I looked at the code for the DoctrineObjectConstructor class, and at the top is a comment:
/**
* Doctrine object constructor for new (or existing) objects during deserialization.
*/
But I don't see how it could possibly create a new a new entity because after the construct() function has done all of its checks, at the end it calls:
$object = $objectManager->find($metadata->name, $identifierList);
And since the identifier does not exist in the database the result is null which is ultimately what gets returned from the function. This explains why inserting a row in the database with the appropriate ID makes things work: find() now returns a proper Entity object, which is what the rest of the library expects.
Am I using the library wrong or is it broken? I forked the Git repo and made an edit, and trying it out everything seems to work more or less the way I expected. That edit does have some drawbacks that make me wonder if I'm not just making this more difficult than it has to be. The biggest issue I see is that it will cause persisted and unpersisted entities to be mixed together with no way to tell which ones are which, but I don't know if that's even a big deal.
For Doctrine entities use configuration:
jms_serializer:
object_constructors:
doctrine:
fallback_strategy: "fallback" # possible values ("null" | "exception" | "fallback")
see configuration reference https://jmsyst.com/bundles/JMSSerializerBundle/master/configuration

NHibernate DateTimeOffsetType proxy source?

I have an existing application using NHibernate to load some fairly complex objects from a database (SQL Server 2008 R2) that has been running for quite some time.
Today, I'm encountering the following error when trying to use JSON.Net to serialize my object:
Error getting value from 'DefaultValue' on 'NHibernate.Type.DateTimeOffsetType'.
None of the properties in my NHibernate mappings are using the DateTimeOffsetType, so I suspect that NHibernate is proxying my objects' properties to that somehow.
I have several Nullable DateTime values on my object, but nothing new to my current release.
Where should I be looking to figure out what properties NHibernate is trying use that type for?
What else might I be missing? The error comes when I attempt to serialize using this code:
var converter = new IsoDateTimeConverter();
x.Json = JsonConvert.SerializeObject(myObject, converter);
Again, that code has been in place for quite some time, it's just the problem that is new.
Not really the solution you will have been looking for perhaps, but a solution none the less - I encountered something similar.
In my case I had forgotten to return my DTO from a web api call and the default json serialiser kicking in did this.
Now I map my data object over to a DTO object which has data contract attributes and I serialize that.
Since my DTO is simple and doesn't get NHibernate Proxified this error no longer seems to occur.
Otherwise - I have done this for other Nullable Dates - where I want more control over the serialisation. Define a custom converter for it and do as you wish, but for this Nhibernate Type.
I'd prefer not serialising (or trying to) those proxy types at all though.
to get to know which properties have datetimeoffset as type
var propertiesWithDateTimeOffset = nhConfiguration.ClassMappings
.SelectMany(c => c.PropertyClosureIterator)
.Where(p => p.Type is DateTimeOffsetType)
.Select(p => p.PersistentClass.ClassName + "." + p.Name);
Note: the code doesn't handle components yet but it would be easy to add

NHibernate: why field.camelcase?

Can someone tell me why in NHibernate mapping we can set access="field.camelcase", since we have access="field" and access="property"?
EDIT: my question is "why we can do this", not "what does it mean". I think this can be source of error for developper.
I guess you wonder what use field.camelcase have when we can do the same with just field? That's true, but that would give (NH) properties unintuive names when eg writing queries or reference the property from other mappings.
Let's say you have something you want to map using the field, eg
private string _name;
public string Name { get { return _name; } }
You sure can map the field using "field" but then you would have to write "_name" when eg writing HQL queries.
select a from Foo a where a._name = ...
If you instead using field.camelcase the data, the same query would look like
select a from Foo a where a.Name...
EDIT
I now saw you wrote "field.camelcase" but my answer is about "field.camelcase-underscore". The principles are the same and I guess you get the point ;)
the portion after the '.' is the so called naming strategy, that you should specify when the name you write in the hbm differ from the backing field. In the case of field.camelcase you are allowed to write CustomerName in the hbm, and NHibernate would look for a field with name customerName in the class. The reason for that is NHibernate not forcing you to choose a name convention to be compliant, NH will works with almost any naming convention.
There are cases where the properties are not suitable for NH to set values.
They may
have no setter at all
call validation on the data that is set, which is not used when loading from the database
do some other stuff that is only used when the value is changed by the business logic (eg. set other properties)
convert the value in some way, which would cause NH performing unnecessary updates.
Then you don't want NH to call the property setter. Instead of mapping the field, you still map the property, but tell NH to use the field when reading / writing the value. Roger has a good explanation why mapping the property is a good thing.

WCF RIA Services SP1, Entity Framework 4, updating only changed columns

I use LinqToEntitiesDomainService class to update database with Silverlight 4 client.
There's AttachAsModified extended method for entity framework ObjectContext which allows you supply original entity property values:
Order original = this.ChangeSet.GetOriginal(currentOrder);
this.ObjectContext.Orders.AttachAsModified(currentOrder, original);
By default, WCF RIA Services doesn't send original values to the server, so one needs to
apply [RoundtripOriginal()] attribute to his/her entity.
However, even if I supply original values, SQL generated by Entity framework updates all columns, not only changed ones. Since AttachAsModified() method isn't native ObjectContext class method (it's extended method defined in ObjectContextExtensions class), I tried to use
ApplyOriginalValues method which is defined in ObjectSet class. No change.
It seems entity framework 4.1, which was released recently may have solution (not sure). How about entity framework 4? Is it possible EF to generate sql to update only changed columns?
AttachAsModified will mark the entity as modified. Subsequently (quote from MSDN):
When you change the EntityState of an
entity object entry to Modified, all
of the properties of the object are
marked as modified, regardless of the
current or original values.
Caveat; I haven't done this but, it should work.
Instead of using AttachAsModified, mark the entity as UnChanged using the ChangeState method.
Then use the SetModifiedProperty method on the properties that have changed to have them included in an update.
EDIT: If you want a way to find which properties have changed, there are a couple of articles out there explaining how to do so using the ObjectStateManager such as this one
I did ask similar question on MSDN forums, and it is confirmed that WCF RIA Services will change all columns. Alternative is,
You can fetch a copy from database, compare and mark SetModifiedProperty manually by using reflection.
// change state of entity as Unmodified/Unchanged...
original.EntityState = Unchanged;
// this is copy form database...
// Use different context
MyOrderContext context = new MyOrderContext();
Order dbOriginal = context.Orders.First( x=>x.OrderID == original.OrderID);
foreach(PropertyInfo p in copy.GetTypes().GetProperties()){
Object originalValue = p.GetValue(dbOriginal);
Object newValue = p.GetValue(original);
if(originalValue!=null && newValue!=null
&& originalValue.Equals(newValue)){
continue;
}
// resetting this will
// make entity's only current
// property as changed
p.SetValue(original,originalValue);
p.SetValue(original,newValue);
}
You may have to change code as per situation, check if property is readonly or not and this is just a sample but it will help you to build upon it.
I managed to do this by first attaching the object and then calling ApplyOriginalValues on the EntitySet. You'll need an object with the original values to do this. This method can also be used to prevent a column from being updated, e.g. for row level security.
NOTE: This unfortunately does not work without retrieving the original entity from the database first. Otherwise only properties that are set to its default value are excluded from the update...

Set Accessor on class does not appear to work with TextInfo and TitleCase

Whilst playing around with an nhibernate mapping, I noticed that a property setter I had was being overloaded (or ignored). This is expected default behaviour with an nhibernate mapping.
So I changed it to use the field.camelCase - so NHibernate would set the private field of the entity class and not the propety getter/setter so I could then use the getter to implement
get { return (new TextInfo()).ToTitleCase(_property);}
I noticed that the output was still what was persisted and this method did not work.
I changed the to _property.ToLower(); and the output was expected as lower case text.
So it appears that there is something I have not done quite right with TextInfo. NHibernate was working correctly (NB NHibernate rocks)
Any ideas why TextInfo is doing this? Probably something trivial I have missed..
For some reason it doesn't work with upper-case strings, uhmmmm Microsoft ;P
Your solution will be to lower case the input first:
get { return (new TextInfo()).ToTitleCase(_property.ToLower());}