By implementing ISubclassConvention, I can change the Discriminator Value for the subclasses in my class hierarchy. I'm now looking for a way to set the Discriminator Value for my base classes as well. Is there a way to change it with a convention override or do I have to add a manual mapping for my hierarchy?
(The IClassConvention provides the DiscriminatorValue property but it is read-only, so no luck there.)
The only way I know is to make simple mapping override just for base class.
public class DepotMappingOverride : IAutoMappingOverride<Depot>
{
/// <summary>
/// Alter the auto mapping for this type
/// </summary>
/// <param name="mapping">Auto mapping</param>
public void Override(AutoMapping<Depot> mapping)
{
mapping.DiscriminateSubClassesOnColumn("Type", "BaseDepot");
}
}
Now "BaseDepot" will be discriminator value for Depot class.
Related
I am having problems with using OptimisticLock as a Convention.
However, using OptimisticLock within Individual ClassMap's works fine. It throws Stale State Object Exceptions.
Each Class corresponding to a Table in the database has a property (which corresponds to a Column in the Table) of type DateTime which I am trying to use for Locking using OptimisticLock.Version().
It works only when I use it within every ClassMap, I don't want to write so many ClassMaps, I instead want to use Auto Mapping.
It WORKS like this within the Class Map
Version(x => x.UpdTs).Column("UPD_TS");
OptimisticLock.Version();
So, I started using Convention below, but it DOESN'T WORK.
OptimisticLock.IsAny(x => x.Version());
I tried setting the DynamicUpdate, etc. Nothing seems to work for me.
Please help !
Here's what I did to get it work using a Convention :
/// <summary>
/// Class represents the Convention which defines which Property/Column serves as a part of the Optimistic Locking Mechanism.
/// </summary>
public class VersionConvention : IVersionConvention, IVersionConventionAcceptance
{
public void Accept(IAcceptanceCriteria<IVersionInspector> criteria)
{
criteria.Expect(x => x.Name == "%COLUMN_NAME%");
}
/// <summary>
/// Method applies additional overrides to the <see cref="IVersionInstance"/>
/// </summary>
/// <param name="instance"><see cref="IVersionInstance"/></param>
public void Apply(IVersionInstance instance)
{
instance.Column("%COLUMN_NAME%");
}
}
%COLUMN_NAME% above is the Property being used for Locking using Version.
Then specified that the Version should be used for Optimistic Locking, when creating a FluentConfiguration Object, like this
OptimisticLock.Is(x => x.Version();
I have a Fluent NHibernate project I'm working on, and doing some testing I have run into a very strange error:
The entity '<>c__DisplayClass3' doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id).
The related entity reported is:
{Name = "<>c__DisplayClass3" FullName = "TPLLCPortal.Domain.Account+<>c__DisplayClass3"}
I don't have any class named DisplayClass, but I do have an Account entity. I'm using a primary key convention that looks like this:
public class PrimaryKeyConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.GeneratedBy.GuidComb();
}
}
My Account class inherits from an EntityBase class that declares the ID as:
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
public virtual Guid Id { get; protected internal set; }
I'm confident that I'm setting up the configuration properly and that the conventions are being picked up, but just in case I added an override and specifically mapped the ID for the Account class. No dice.
Any ideas what's going on here?
I'm using FNH 1.3.0.733 with NHibernate 3.3.1.4000 (both loaded off NuGet).
Looks like I figured it out. This SO answer had the key. Because some of the methods on the class use lambdas, the compiler creates classes that you can exclude in the DefaultAutomappingConfiguration by specifying !type.IsDefined(typeof(CompilerGeneratedAttribute), false) as part of the ShouldMap override.
I have an abstract base class which inherits Sharp Arch's Entity class:
/// <summary>
/// defines an entity that will ne indexed by a search crawler and offered up as full-text searchable
/// </summary>
public abstract class IndexedEntity : Entity
{
[DocumentId]
public override int Id
{
get { return base.Id; }
protected set { base.Id = value; }
}
}
This is to a legacy db and actually the Id column is called "HelpPageID", so I have some mapping override as:
mapping.Id(x => x.Id, "HelpPageID");
The generated sql for querying HelpPage works fine when I simply inherit Entity. But inheriting IndexedEntity, when translated to sql, the column name override is ignored and instead Id is used for the column, thus failing.
Edit
Seems a general issue with an override as placing the override directly in the class has the same net effect
mapping overrides are only executed for the exact type not types which subclass the type in the mappingoverride. you have to specify an override for the subclass.
This may be old news but back in March 2009, this article, “Model-View-ViewModel In Silverlight 2 Apps,” has a code sample that includes DataServiceEntityBase:
// COPIED FROM SILVERLIGHTCONTRIB Project for simplicity
/// <summary>
/// Base class for DataService Data Contract classes to implement
/// base functionality that is needed like INotifyPropertyChanged.
/// Add the base class in the partial class to add the implementation.
/// </summary>
public abstract class DataServiceEntityBase : INotifyPropertyChanged
{
/// <summary>
/// The handler for the registrants of the interface's event
/// </summary>
PropertyChangedEventHandler _propertyChangedHandler;
/// <summary>
/// Allow inheritors to fire the event more simply.
/// </summary>
/// <param name="propertyName"></param>
protected void FirePropertyChanged(string propertyName)
{
if (_propertyChangedHandler != null)
{
_propertyChangedHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
#region INotifyPropertyChanged Members
/// <summary>
/// The interface used to notify changes on the entity.
/// </summary>
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add
{
_propertyChangedHandler += value;
}
remove
{
_propertyChangedHandler -= value;
}
}
#endregion
What this class implies is that the developer intends to bind visuals directly to data (yes, a ViewModel is used but it defines an ObservableCollection of data objects). Is this design diverging too far from the guidance of MVVM? Now I can see some of the reasons Why would we go this way: what we can do with DataServiceEntityBase is this sort of thing (which is intimate with the Entity Framework):
// Partial Method to support the INotifyPropertyChanged interface
public partial class Game : DataServiceEntityBase
{
#region Partial Method INotifyPropertyChanged Implementation
// Override the Changed partial methods to implement the
// INotifyPropertyChanged interface
// This helps with the Model implementation to be a mostly
// DataBound implementation
partial void OnDeveloperChanged() { base.FirePropertyChanged("Developer"); }
partial void OnGenreChanged() { base.FirePropertyChanged("Genre"); }
partial void OnListPriceChanged() { base.FirePropertyChanged("ListPrice"); }
partial void OnListPriceCurrencyChanged() { base.FirePropertyChanged("ListPriceCurrency"); }
partial void OnPlayerInfoChanged() { base.FirePropertyChanged("PlayerInfo"); }
partial void OnProductDescriptionChanged() { base.FirePropertyChanged("ProductDescription"); }
partial void OnProductIDChanged() { base.FirePropertyChanged("ProductID"); }
partial void OnProductImageUrlChanged() { base.FirePropertyChanged("ProductImageUrl"); }
partial void OnProductNameChanged() { base.FirePropertyChanged("ProductName"); }
partial void OnProductTypeIDChanged() { base.FirePropertyChanged("ProductTypeID"); }
partial void OnPublisherChanged() { base.FirePropertyChanged("Publisher"); }
partial void OnRatingChanged() { base.FirePropertyChanged("Rating"); }
partial void OnRatingUrlChanged() { base.FirePropertyChanged("RatingUrl"); }
partial void OnReleaseDateChanged() { base.FirePropertyChanged("ReleaseDate"); }
partial void OnSystemNameChanged() { base.FirePropertyChanged("SystemName"); }
#endregion
}
Of course MSDN code can seen as “toy code” for educational purposes but is anyone doing anything like this in the real world of Silverlight development?
In order to make a View entirely independent of the Model you would need to reproduce types that in many cases are identical to the Model types in your ViewModel.
Example
A Model contains a Person type that have FirstName and LastName properties. The visual design calls for a "List of people" so there is a View containing a ListBox that has a data template binding to property paths of FirstName and LastName. The ItemsSource binds to a property of ViewModel that exposes a set instances of types that have a FirstName and LastName property.
So here is the question, should there be a "ViewModel version" of the Model Person type or should the ViewModel simply re-use the existing Person type from the Model?
In either case its quite possible that you would want the properties to be observable.
To consider
What are the objectives behind MVVM? Quite often we like to present nice long lists of why a pattern exists but in this case there are really only 2.
Separate visual design (note: not design) from code.
Maximise the testable surface of the overall application.
Exposing Model types on the ViewModel doesn't form an obstacle to either of the above objectives. In fact it aids testability since the number of types and members that need testing is reduced.
In my opinion I don't see that implementing INotifyPropertyChanged implies binding to visuals. There may be other reasons why some service may want to observe changes in properties of a model object.
The key principle in the separation of Model from View is hiding of any specifics about the how the View presents the Model from the Model itself. Adding a ForenameBackColor property to the Model would be probably be bad. This is where the ViewModel comes in.
Bottom Line
Requiring the Model to expose observable properties is not breach of MVVM, its a simple and general requirement that does not require the Model to have any specific knowledge of any View or indeed that there are any "visuals" involved at all.
No, looks fine to me - DataServiceEntityBase is just the name of his base class which all his DTO's/business objects inherit from, nothing wrong with that setup (did that name throw you a little?). If he is putting his data in a ViewModel and then binding his View to the VM then you at least have the VVM part of MVVM.
The main thing i would be upset about is his naming of the FirePropertyChanged method - personally i would have called it OnPropertyChanged.
Whenever I use WCF, I always try to make immutable classes that end up going over the wire (i.e. parameters set in constructor, properties are read-only). However, this gets in the way of WCF serialization, which demands that all properties be Public get/set (which makes sense, because it has to deserialize them)
Even in this related post, I see that their solution ended up making everything Public, which violates my sense of good programming. Is there any way around this? Do I have to just settle for this solution or something like popsicle immutability and be happy with it?
The other thing I tried was something like this, where I'd have a base class for everything and a derived class that made the set useless:
/// <summary>
/// This represents a discovered virtual-machine template that can be
/// instantiated into a RunningVirtualMachine
/// </summary>
[DataContract]
[XmlRoot("VMTemplate")]
public class VirtualMachineTemplateBase
{
[DataMember]
public virtual ulong SizeInBytes { get; set; }
}
/// <summary>
/// This class is the real guts of VirtualMachineTemplate that we're hiding
/// from the base class.
/// </summary>
[XmlInclude(typeof(VirtualMachineTemplateBase))]
public class VirtualMachineTemplate : VirtualMachineTemplateBase, IXmlPicklable, IEnableLogger
{
ulong _SizeInBytes;
public override ulong SizeInBytes {
get { return _SizeInBytes; }
set { }
}
}
If you use the DataContractSerializer (which is the default for WCF), you can serialize anyhting that's decorated with the [DataMember] attribute - even a read-only field:
[DataContract]
public class VirtualMachineTemplate : VirtualMachineTemplateBase, IXmlPicklable, IEnableLogger
{
[DataMember]
ulong _SizeInBytes;
}
But you need to use the DataContractSerializer - not the XML serializer. The XML serializer can ONLY serialize public properties (and it will, unless you put a [XmlIgnore] on them).
The DataContractSerializer is different:
it doesn't need a parameter-less default constructor
it will only serialize what you explicitly mark with [DataMember]
but that can be anything - a field, a property, and of any visibility (private, protected, public)
it's a bit faster than XmlSerializer, but you don't get a lot of control over the shape of the XML - you only get a say in what's included
See this blog post and this blog post for a few more tips and tricks.
Marc
To ensure both immutability and easy implementation at the same time add a private setter for the property to serve deserialization. A lot happens under the bonnet, but it works.