views:

124

answers:

2

I have a db setup with 3 tables

t_DataItem
 pk id int auto
 isActive bit 0
 dateCreated datetime getdate()
 parentId int null

t_User
 pk id int 
 firstName varchar(50)
 lastName varchar(50)

t_Email
 pk id int
 address varchar(50)

so now i have 3 classes, each one representing the respective item, however both User and Email inherit from DataItem.

public class DataItem
    {
        public virtual int Id { get; private set; }
        public virtual DateTime DateCreated { get ; set; }
        public virtual bool IsActive { get; set; }
        public virtual DataItem Parent { get; set; }

        public DataItem()
        {
            DateCreated = DateTime.Now;
        }
    }


public class Email : DataItem
    {
        public virtual string Address { get; set; }
    }

public class User : DataItem
    {
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }

        public virtual IList<Email> Emails { get; private set; }

        public  User()
        {
            Emails = new List<Email>();
        }

        public virtual void AddEmail(Email email)
        {
            Emails.Add(email);
        }
    }

So when I save a user or email, it should save a dataitem record first, passing it's id to the id of user or email (any subclass really).

I have that portion working.. my problem lies in the mapping for setting up the

DataItem Mapping to have a Reference to parent, and the HasMany in the UserMap that corresponds to the emails.

I can't get it to save the Email, with it's DataItem ParentId filled out to the User.Id

So if I had a user record, i should have a corresponding dataitem record

if I had an email record, I should have a corresponding dataItem record with it's parentId set to the id of the user record id.

Hopefully I've explained that right...

Can someone please show me an example of how I would map this out using Fluent NHibernate?

My mappings are as follows

public class DataItemMap : ClassMap<DataItem>
    {
        public DataItemMap()
        {
            Table("t_DataItem");
            Id(map => map.Id);
            Map(map => map.DateCreated).Nullable();
            Map(map => map.IsActive);
            References(map => map.Parent).Column("parentid");
        }
    }

public class EmailMapping : SubclassMap<Email> 
    {
        public EmailMapping()
        {
            Table("t_emails");
            KeyColumn("id");
            Map(email => email.Address);
        }
    }

public class UserMapping : SubclassMap<User>
    {
        public UserMapping()
        {
            Table("t_Users");
            KeyColumn("id");
            Map(user => user.FirstName);
            Map(user => user.LastName);
            HasMany(user => user.Emails).KeyColumn("id").Cascade.All();
        }
    }

I love how it auto creates the dataitem record and grabs it's id and stores it into my user or email table.. now if i could get the last piece of the puzzle figured out where when i save an email, not only does it save the dataitem record, but fills out the parentid, and then when i pull the emails for a user, it checks the user id against the parent id on the join..

if this level of inheritance isn't possible, please let me know.

if it is, could you please provide me to the proper tutorial or help by correcting my class maps?

thanks!

A: 

figured it out

i had to change my HasMany mapping to include the DataItem type so that it knew to pull the field parentId from the DataItem table instead of my email table (where the field doesn't exist)

HasMany<DataItem>(user => user.Emails).KeyColumn("parentid").Cascade.All();

then in my User class change the method AddEmail to

public virtual void AddEmail(Email email)
{
    email.Parent = this;  //forgot to set it's parent..
    Emails.Add(email);
}

awesome tool.. very powerful!

mike
A: 

hmm actually when i save a new user, assigning an email and phone number.. then request the session to retrieve the data it works.. but if i do a blank request without having inserted any data into the database it fails? stating that phone is not type of email ????

it gives a very odd sql statement too

why is it joining the email and phone together? my mapping must be really messed up still... but it's odd the first time i insert data and make a request right away it returns the data fine..

var u = new User { FirstName = "jimmy", LastName = "k" };
            u.AddEmail(new Email { Address = "[email protected]" });
            u.AddPhone(new Phone { CountryCode = 12, IsActive = true, Number = 8888, Prefix = 777 });
            session.SaveOrUpdate(u);

then if i call var users = session.CreateCriteria(typeof (User)).List<User>();

it comes back with the users and their emails/phone numbers...

but if i comment out the session.SaveOrUpdate(u); and execute the createCriteria.. it fails????

below is the odd sql statement that the profiler recorded

SELECT emails0_.parentId      as parentId1_,
   emails0_.Id            as Id1_,
   emails0_.Id            as Id0_0_,
   emails0_.DateCreated   as DateCrea2_0_0_,
   emails0_.IsActive      as IsActive0_0_,
   emails0_.ParentID      as ParentID0_0_,
   emails0_1_.FirstName   as FirstName1_0_,
   emails0_1_.LastName    as LastName1_0_,
   emails0_2_.Address     as Address2_0_,
   emails0_3_.CountryCode as CountryC2_3_0_,
   emails0_3_.Number      as Number3_0_,
   emails0_3_.Prefix      as Prefix3_0_,
   case 
     when emails0_1_.id is not null
     then 1
     when emails0_2_.id is not null
     then 2
     when emails0_3_.id is not null
     then 3
     when emails0_.Id is not null
     then 0
   end as clazz_0_
FROM   t_DataItem emails0_
       left outer join t_User emails0_1_
         on emails0_.Id = emails0_1_.id
       left outer join t_email emails0_2_
         on emails0_.Id = emails0_2_.id
       left outer join t_phone emails0_3_
         on emails0_.Id = emails0_3_.id
WHERE  emails0_.parentId = 1 /* @p0 */
mike