"Tried to add property 'Id' when already added."-Error when implementing own class twice - fluent-nhibernate

I would like to have a mapped class named "Message". This class should include an unique id, the title, the text, and information about the sender and the receiver. I need their User-ID an their name, so I've created another class named "User". This class include these two properties (later I'll create some methods for this class and use it in different classes, so I can not use onyl the class "Message").
This is my code
public class User
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
}
public class Message
{
public virtual Guid Id { get; set; }
public User sender;
public User receiver;
public virtual string subject { get; set; }
public virtual string text { get; set; }
}
public class MessageMap : ClassMap<Message>, IMappedEntity
{
public MessageMap()
{
Id(x => x.Id, "MessageId");
Map(x => x.sender.Id, "SenderId");
Map(x => x.receiver.Id, "ReceiverId");
Map(x => x.subject);
Map(x => x.text);
}
}
As you can see, I want to save only the User-ID of the sender and receiver, not their names. Because x.Id, x.sender.Id and x.receiver.Id have the property "Id", I wrote down a spezific name for them in the database.
But if I try to load the site, this error appears: Tried to add property 'Id' when already added., even if their is no more property named "Id" after I definited the Name for the columns...
Could you give me a hint what I'm doing wrong?

I finally found an other solution: I changed the mapping of my Message-Map to this:
public class MessageMap : ClassMap<Message>, IMappedEntity
{
public MessageMap()
{
Id(x => x.Id);
Component(
x => x.sender,
userId =>
{
userId.Map(x => x.Id, "senderId");
}
);
Component(
x => x.receiver,
userId =>
{
userId.Map(x => x.Id, "receiverId");
}
);
Map(x => x.subject);
Map(x => x.text);
}
Now, I do not have to map the User-Class, so I don't have a table only with my Userids.
I'm not too familar with using nHibernate, so I'm not shure wether this is the best way to solve the problem, but in my eyes this fits a bit more to my problem then the solution presented by Chev (but I'm very grateful that you have answered me!)

Change the MessageMap as follows.
public class MessageMap : ClassMap<Message>, IMappedEntity
{
public MessageMap()
{
Id(x => x.Id);
References(x => x.Sender);
References(x => x.Receiver);
Map(x => x.subject);
Map(x => x.text);
}
}

Related

Table-per-subclass fluent nhibernate not working

I have the following classes defined:
And these tables in my database:
My fluent NHibernate mappings are:
public class BusinessUnitMap : ClassMap<BusinessUnit>
{
public BusinessUnitMap()
{
Table("BusinessUnits");
Id(x => x.Id);
Map(x => x.Code);
Map(x => x.Name);
Map(x => x.ParentId);
Map(x => x.Type).Column("Type").CustomType<BusinessUnitType>();
}
}
public class CompanyMap : SubclassMap<Company>
{
public CompanyMap()
{
Table("CompanyData");
KeyColumn("BusinessUnitID");
Map(x => x.Something);
}
}
public class FranchiseeMap : SubclassMap<Franchisee>
{
public FranchiseeMap()
{
Table("FranchiseeData");
KeyColumn("BusinessUnitID");
Map(x => x.SomethingDifferent);
}
}
public class StoreMap : SubclassMap<Store>
{
public StoreMap()
{
Table("StoreData");
KeyColumn("BusinessUnitID");
Map(x => x.SomethingElse);
}
}
Question #1
As far as I can tell, my code and database are setup the same as every example I've been able to find. According to those articles, NHibernate is supposed to be smart enough to determine what subclass to instantiate when I query for a particular subclass. But, when I execute the following statement:
var result = Session.QueryOver<BusinessUnit>()
.Where(x => x.Code == "Acme")
.SingleOrDefault();
an exception is thrown because it can't create an instance of the abstract BusinessUnit class. The only way I can get this to work is to specify Company as the type argument for QueryOver.
I've confirmed that using a discriminator breaks since NHibernate is looking for all of the columns to exist in a single table. Without it, though, I struggle to see how NHibernate would know what type to instantiate.
What am I doing wrong? Is the problem in my mappings, the way I'm querying, ...?
Question #2
When I change the query to something like this:
public T WithCode<T>(String code)
where T : BusinessUnit
{
var result = Session.QueryOver<T>()
.Where(x => x.Code == code)
.SingleOrDefault();
return result;
}
I get an exception indicating that the UPDATE statement conflicts with a foreign key constraint. Update statement!!!! Clearly something is still not right. How can a QueryOver call result in an UPDATE statement? What am I missing?
it looks like your data is not consistent. It might be better to use discrimnator mapping with optional. If you dont really need a BusinessUnitType property in code then just delete everything around the property Type
public enum BusinessUnitType
{
Company,
Franchisee
}
public abstract class BusinessUnit
{
public virtual int Id { get; set; }
public virtual string Code { get; set; }
public virtual string Name { get; set; }
public virtual BusinessUnit Parent { get; set; }
public abstract BusinessUnitType Type { get; }
}
public class Company : BusinessUnit
{
public virtual string Something { get; set; }
public override BusinessUnitType Type { get { return BusinessUnitType.Company; } }
}
public class Franchisee : BusinessUnit
{
public virtual string SomethingDifferent { get; set; }
public override BusinessUnitType Type { get { return BusinessUnitType.Franchisee; } }
}
public class BusinessUnitMap : ClassMap<BusinessUnit>
{
public BusinessUnitMap()
{
Table("BusinessUnits");
Id(x => x.Id);
Map(x => x.Code);
Map(x => x.Name);
References(x => x.Parent);
DiscriminateSubClassesOnColumn("Type");
Map(x => x.Type, "Type")
.Access.None()
.CustomType<BusinessUnitType>().ReadOnly();
}
}
public class CompanyMap : SubclassMap<StrangeTablePerSubclass.Company>
{
public CompanyMap()
{
DiscriminatorValue((int)new Company().Type);
Join("CompanyData", join =>
{
join.KeyColumn("BusinessUnitID");
join.Optional();
join.Map(x => x.Something);
});
}
}
public class FranchiseeMap : SubclassMap<Franchisee>
{
public FranchiseeMap()
{
DiscriminatorValue((int)new Franchisee().Type);
Join("FranchiseeData", join =>
{
join.KeyColumn("BusinessUnitID");
join.Optional();
join.Map(x => x.SomethingDifferent);
});
}
}

Stop fluent from generating double foreign keys

When I generate my database from fluent one of my tables as 2 of every field and I can't figure out why
like I have the fk keys how I want them too look(StudentId) but it also generates the keys how they want it to look(student_id)
public class PermissionLevel
{
public virtual int PermissionLevelId { get; private set; }
public virtual Student Student { get; set; }
public virtual Course Course { get; set; }
public virtual Permission Permission { get; set; }
}
public class PermissionMap : ClassMap<Permission>
{
public PermissionMap()
{
Table("Permissions");
Id(x => x.PermissionId).Column("PermissionId");
Map(x => x.Name).NvarcharWithMaxSize().Not.Nullable();
HasMany(x => x.PermissionLevels);
}
}
public class PermissionLevelMap : ClassMap<PermissionLevel>
{
public PermissionLevelMap()
{
Table("PermissionLevels");
Id(x => x.PermissionLevelId).Column("PermissionLevelId");
References(x => x.Permission).Not.Nullable().Column("PermissionId");
References(x => x.Student).Not.Nullable().Column("StudentId");
References(x => x.Course).Not.Nullable().Column("CourseId");
}
}
public class StudentMap : ClassMap<Student>
{
public StudentMap()
{
Table("Students");
Id(x => x.StudentId).Column("StudentId");
HasMany(x => x.PermissionLevels);
}
}
all mine look like that and I get
(source: gyazo.com)
ISessionFactory fluentConfiguration = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("Connection")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Framework.Data.Mapping.StudentMap>())
.ExposeConfiguration(BuidSchema)
.BuildSessionFactory();
I wasn't able to duplicate the issue, but try this: in your configuration, change the mappings to include a convention for the foreign key names like:
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Framework.Data.Mapping.StudentMap>().Conventions.Add(ForeignKey.EndsWith("Id"))
With that in place, you can remove the Column() call from the individual mapping files and achieve the same result. Since I can't reproduce your exact issue, I'm hoping this will also clear up the problem (I have a hunch that Fluent's AutoMap feature is getting in the mix somehow but it doesn't look like your code is allowing for this, so it really is just a hunch).

fluent nhibernate component one-to-many

I have couple of classes and want to map them correctly to database:
public class A
{
public virtual Guid Id { get; private set; }
public virtual ComponentClass Component { get; set; }
}
public class ComponentClass
{
public virtual IList<B> Elements { get;set; }
}
public class B
{
public virtual Guid Id { get; private set; }
public virtual DateTime Time { get; set; }
}
I map them using fluent mappings like that:
public class AMap : ClassMap<A>
{
public A() {
Id(x => x.Id);
Component(x => x.Component,
c => c.HasMany(x => x.Elements).Inverse().Cascade.All());
}
}
public class BMap : ClassMap<B>
{
public B() {
Id(x => x.Id);
Map(x => x.Time);
}
}
When I save my entity, I have class A mapped to one table and class B to another as expected.
But I have nulls in Component_id column.
Can you tell me what am I missing here?
I believe Components are supposed to be in the same table , as clearly stated in Ayende's blog post, as they serve only to make the data better represented as an object model. Be sure to read through his blog, it's probably one of the best nHibernate resources out there.
Ok, I've resolved my problem - I can use Id of my "parent" class. So the component mapping will become:
public class AMap : ClassMap<A>
{
public A() {
Id(x => x.Id);
Component(x => x.Component,
c => c.HasMany(x => x.Elements).Cascade.All().Column("Id"));
}
}
So obvious as I look at it now ... but It took me an hour.
If you have a one-to-many association direct to a collection of components (ie. without the ComponentClass wrapper as per the question) then you can map it directly:
HasMany(x => x.Elements)
.AsSet()
.Table("ElementTable")
.KeyColumn("KeyColumn")
.Cascade.All()
.Component(x =>
{
x.Map(c => c.Id);
x.Map(c => c.Time);
})
.LazyLoad();

FluentNHibernate IDctionary with manytomany

I have a mapping structured in this way:
public class Person
{
public IDictionary<bool, Action> Actions { get; set; }
}
public class Action
{
public string Name { get; set; }
}
// Map for Person
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Id(x => x.Id) ...
Map(x => x.Name) ...
Table("Persons")
}
}
// Map for Action
public class ActionMap : ActionMap<Action>
{
public ActionMap()
{
Id(x => x.Id) ...
Map(x => x.Name) ...
Table("Actions")
}
}
What I need to do now is this.
I need a third table that will contains this fields:
PersonId
ActionId
True/false
Because I have the collection of actions inside the class person i was thinking about using a manytomany, but I can't find documentation on how to map an IDictionary.
Any idea? Wrong approach?
Dunno if you've already found the solution but there's been a recent update(only a couple weeks ago) where you could simply map it as HasManyToMany(x => x.NameOfDictionary) so you might want to update your FNH.
I haven't tried it yet though but here's the link: mailing list post

NHibernate Mapping Question

I have tried various approaches to mapping the following structure, but I finally admit that after a day of not getting very far, I need some help.
So the question is, how would you guys go about mapping something like this. The schema is not fixed at this point.
public abstract class BaseObject
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual string Prefix { get; set; }
public virtual string Suffix { get; set; }
public virtual BaseObject Parent { get; set; }
}
public class Room : BaseObject
{
public virtual int AreaId { get; set; }
}
public class Item : BaseObject
{
public virtual string Owner { get; set; }
public virtual IList<ItemAttribute> Attributes { get; set; }
public virtual int ItemTypeId { get; set; }
}
public class Potion : Item
{
public virtual int AmountLeft { get; set; }
}
Your input is very much appreciated.
This allows you to have it all in one table... doing this from memory, so syntax might not be exact.
public class ItemMap : ClassMap<BaseObject>
{
...
WithTable("objects");
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name);
Map(x => x.Description);
...
DiscriminateSubClassesOnColumn("Type")
.SubClass<Room>("Room", x =>
{
x.Map(r => r.AreaId);
})
.SubClass<Item>("Item", c =>
{
i.Map(x => x.Owner);
i.References(x => x.Account).LazyLoad();
HasManyToMany(x => x.Attributes)
.WithParentKeyColumn("ItemId")
.WithChildKeyColumn("AttributeId")
.WithTableName("ItemAttributes")
.LazyLoad();
});
.SubClass<Potion>("Potion", x =>
{
x.Map(p => p.AmountLeft);
})
I would probably have a table for each class - Room, Item, Potion and then do fairly standard mappings for each.
I'd like to note that in my own experiences, it is a bad idea to name your Id field in your business objects "Id"
Here's a sample with Item, assoming some data names for your table.
public class ItemMap : ClassMap<Item>
{
public ItemMap()
{
WithTable("Items");
Id(x => x.Id, "ItemId").GeneratedBy.Identity();
Map(x => x.Name);
Map(x => x.Description);
Map(x => x.Prefix);
Map(x => x.Suffix);
Map(x => x.Owner);
Map(x => x.ItemTypeId);
References<Item>(x => x.Parent, "ParentItemId");
HasManyToMany(x => x.Attributes)
.WithParentKeyColumn("ItemId")
.WithChildKeyColumn("AttributeId")
.WithTableName("ItemAttributes")
.LazyLoad();
}
}
This is more than likely not be perfect - as I'm not sure how the mapping will work with the abstract parent.