Mapping an inherited Id from related entity.

Oct 25, 2010 at 9:41 AM
Edited Oct 25, 2010 at 9:43 AM

I have an entity base class that has an Id. I then inherit off this class with all my other entities (since they all have Id's).

        
    public abstract class Entity : IEntity
    {
       private int id;

        public virtual int Id
        {
            get
            {
                return this.id;
            }
            protected set
            {
                this.id = value;
            }
        }

 

        public class ProgrammeClient : Entity, IProgrammeClient
{
public virtual IProgramme Programme { get; set; }

public virtual IClient Client { get; set; }
 
    public class Client : EntityIClient
    {
        public virtual string Name { getset; }


I am able to map correctly to a ViewModel with viewmodel.InjectFrom<FlatLoopValueInjection>(programmeClient);

		public ProgrammeClientViewModel(IProgrammeClient programmeClient, SelectList countryList)
{
this.InjectFrom<FlatLoopValueInjection>(programmeClient);

                        //Not mapped so set manually
                        //this
.ClientId = programmeClient.Client.Id;
                        this.CountryList = countryList;

}

This is setting all the properties correctly;

this.Id (programmeClient's  Id) //Correct,

this.ClientName (programmeClient.Client.Name) //Correct,

but this.ClientId is 0 despite programmeClient.Client.Id being the correct Id.

Is there something i am doing wrong? - I dont understand why name is mapping correctly on Client but the Id is not and i can only assume inheritance is the issue.

I googled this problem for Automapper and there was a solution to a problem like this that mentioned needing a setter on the base Entity. (I was missing this) but when i added it, there was no difference.

Many thanks.

Coordinator
Oct 25, 2010 at 9:46 AM

Hi,

the problem is that your setter is protected, it needs to be public

even if you would do it manually

entity.Id = 5 it's not gonna work, you're gonna have a compile time error

 

so, you need something like this:

public virtual int Id { get;set; }

 

Oct 25, 2010 at 9:53 AM

Thanks for the prompt reply, but no joy i am afraid.

    public interface IEntity
    {
        /// <summary>
        /// Gets the unique identifier for the entity
        /// </summary>
int Id { getset; }
    }

    public abstract class Entity : IEntity
    {
        int id;

        /// <summary>
        /// Gets the unique identifier for the entity.
        /// </summary>
        public virtual int Id
        {
            get
            {
                return this.id;
            }
            set
            {
                this.id = value;
            }
        }

The thing i am finding odd is that this.Id (which programmeClient inherits) is getting mapped. But programmeClient.Client.Id is not.
Coordinator
Oct 25, 2010 at 11:12 AM

could you show me the ProgrammeClientViewModel class ?

Oct 25, 2010 at 11:21 AM
Edited Oct 25, 2010 at 11:22 AM


namespace Project.ViewModels
{
public class ProgrammeClientViewModel
{
public ProgrammeClientViewModel() { }

public ProgrammeClientViewModel(IProgrammeClient programmeClient, SelectList countryList)
{
this.InjectFrom<FlatLoopValueInjection>(programmeClient);
this.ClientId = programmeClient.Client.Id; //Not mapped so set manually
                       this
.ClientAddressCountryId = programmeClient.Client.Address.Country.Id; //Also not mapped
this.CountryList = countryList;
}
               
                public
 int Id { getset; } //Set okay (inherits from IEntity base class)

public int ClientId { getset; } //Not set (inherits from IEntity base class)

[DisplayName("Name:")]
[Required(ErrorMessage = "Please enter a client name.")]
public string ClientName { getset; }

[DisplayName("Country:")]
[Required(ErrorMessage = "Please select a country for the client's address.")]
public int ClientAddressCountryId { getset; }

public SelectList CountryList { getset; }
}
}
Coordinator
Oct 25, 2010 at 12:10 PM
this.ClientId = programmeClient.Client.Id; //Not mapped so set manually

the code that you showed me can't compile because your IClient doesn't has a property Id

and your ProgrammeClient.Client is of type IClient
Oct 25, 2010 at 12:15 PM

Correct,

IClient doesn't have an Id itself, it inherits off IEntity that has an Id.

IProgrammeClient doesn't have an Id either (It also inherits from IEntity) but this is getting set fine (this.Id)

Is this a limitation?

Coordinator
Oct 25, 2010 at 12:28 PM

ok, I think that will be better if you will give me both classes entity and the viewmodel, with everything else concerning the mapping

Oct 25, 2010 at 2:07 PM
Edited Oct 25, 2010 at 2:08 PM
public interface IEntity
    {
        int Id { get; set;}
    }

    public abstract class Entity : IEntity
    {
        int id;

        public virtual int Id
        {
            get
            {
                return this.id;
            }
            set
            {
                this.id = value;
            }
        }
     }

public class ProgrammeClient : Entity, IProgrammeClient
{
public virtual IProgramme Programme { get; set; }

public virtual IClient Client { get; set; }
        }
 
    public class Client : EntityIClient
    {
        public virtual string Name { getset; }
     }

It may be worth noting that it seems affect any id that is coming through a relation,
 for example ... parentEntity.SomeRelatedEntity.Id will not map but parentEntity.Id will be fine.

Also using intellisence on SomeRelatedEntity will not show an Id, I have to look at the Proxy class
 on the object to find the Id (I am using Fluent NHibernate), i suspect this might be where the problem lays.

Thanks for the help with this, much appreciated.
Coordinator
Oct 25, 2010 at 3:03 PM

Hi,

it looks like a .NET bug

the PropertyDescriptor.GetChildProperties() doesn't return the properties from the inherited interface (GetChildProperties(instance) does )

I found a workaround and I will do a new version release as fast as I can (1 or 2 days)

for the moment you can use Client as a property type instead of IClient in your classes and it is going to work

Cheers,

Omu

Oct 25, 2010 at 3:07 PM

Excellent, many thanks for looking into this!

Kind regards,

Kohan.

Coordinator
Oct 28, 2010 at 8:34 AM

ok, it's done, you can try the new version 2.1

Good Luck

Omu

Oct 28, 2010 at 10:17 AM

Excellent, seems to work like a charm.

A BIG thanks to you!