FluentNhibernate IDictionary<Entity,ValueObject> - nhibernate

I had a mapping for a IDictionary<StocksLocation,decimal> property, this was the mapping:
HasMany<StocksLocation>(mq => mq.StocksLocation)
.KeyColumn("IDProduct")
.AsEntityMap("IDLocation")
.Element("Quantity", qt => qt.Type<decimal>());
Now i changed from decimal to a Value Object: Quantity.
Quantity has two properties, decimal Value and Unit Unit (where Unit is an enum).
I now have to map IDictionary<StocksLocation,Quantity>, how can i achieve this?
Thanks in advance

Option 1: Map it as an Entity
I'm guessing that your table looks similar to this:
CREATE TABLE Quantity (
ID int NOT NULL,
IDProduct int NOT NULL,
IDLocation int NOT NULL,
Value decimal(18,2) NOT NULL,
Unit int NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (IDProduct) REFERENCES Product (ID),
FOREIGN KEY (IDLocation) REFERENCES StocksLocation (ID),
UNIQUE KEY (IDProduct, IDLocation)
);
Go ahead and map Quantity as an entity class:
public class QuantityMap : ClassMap<Quantity>
{
public QuantityMap()
{
Id(x => x.Id);
References(x => x.Product, "IDProduct");
References(x => x.Location, "IDLocation");
Map(x => x.Value);
Map(x => x.Unit);
}
}
... and then change the Product.StocksLocation mapping to:
HasMany<StocksLocation, Quantity>(mq => mq.StocksLocation)
.KeyColumn("IDProduct")
.AsMap(x => x.Location);
Option 2: Map it as a Component
Because you commented that you'd rather not map Quantity as an entity, let's consider how we would map this as a component instead. The *.hbm.xml mapping for the Product.StocksLocation dictionary would look like this:
<map name="StocksLocation" table="Quantity">
<key column="IDProduct" />
<index-many-to-many column="IDLocation" class="YourNamespace.StocksLocation, YourAssembly" />
<composite-element class="YourNamespace.Quantity, YourAssembly">
<property name="Unit" type="YourNamespace.Unit, YourAssembly" />
<property name="Value" type="System.Decimal, mscorlib" />
</composite-element>
</map>
How do we do this with FluentNHibernate? As far as I know, there isn't a method for doing this in the trunk, so you have a few options:
Gabriel Schenker implemented a HasManyComponent method. He has a link to the source code for his project, but I don't know whether that source includes the changes he made to FluentNHibernate.
If the source for his changes are not available, feel free to implement your own modifications to FluentNHibernate and submit them back to the community via Github.
If that sounds like too much trouble, FluentNHibernate has an ultimate fallback when all else fails. It allows you to mix and match various mapping methods. Auto-map some of your classes, write ClassMap classes for others, and write a *.hbm.xml file for any classes that can't be mapped with FluentNHibernate.

Related

Convert Mapping from XML to Confirmst(Code Mappings)

Hello I am presently converting the xml mappings to code mappings and I am stuck at one place as I am not getting the proper way to convert ManyToOne Mappings.
The XML Mappings are
</many-to-one>
<many-to-one class="MyProject.Activity.Communication, MyProject.Activity" name="Comm">
<column name="CommID" />
</many-to-one>
Now I have this MyProject.Activity.Communication in other solution and don't have any reference in my mapping project. I want to specify class in my code mappings.
ManyToOne(x => x.Comm, map =>
{
map.Column("CommID");
});
How do I specify class in this mapping as the Entity name is referenced so I need to add the class in my code mappings.
The mappings would be using Reflection to fetch the assembly name.
ManyToOne(x => x.Survey, map =>
{
map.Column("SurveyID");
map.Class(Type.GetType("MyProject.Activity.Communication, MyProject.Activity"));
});

mapping (by code - not fluent) an FK column as a list of enums in parent entity

I have an entity class that represents a person and an enum that represents permissions that a person has. I am trying to map this relationship to a database using nhibernate mapping by code without any success.
The code looks like this:
public enum Permissions
{
None = 1,
CanUpdate = 2,
CanInsert = 3,
CanDelete = 4
}
public class Person
{
private ICollection<Permissions> permissions;
public Person()
{
this.permissions = new Collection<Permissions>();
}
public virtual ICollection<Permissions> Permissions
{
get
{
return this.permissions;
}
}
}
public class PersonMap : ClassMapping<Person>
{
public PersonMap()
{
this.Set(
x => x.Permissions,
m =>
{
m.Access(Accessor.Field);
m.Key(k => k.Column("PersonId"));
m.Table("PersonHasPermission");
},
map => map.Element(
p =>
{
p.Column("PermissionId");
p.Type<NHibernate.Type.EnumType<Permissions>>();
}));
}
}
The database tables look like this:
Person
-----------------------
PersonId (PK, uniqueidentifier, not null)
Name (nvarchar(max), not null)
PersonHasPermission
-----------------------
PersonId (PK, FK, uniqueidentifier, not null)
PermissionId (PK, FK, int, not null)
So, with this configuration I do not get any exceptions but whenever I try to fetch the permissions for a person the collection is always empty even though there is data in the database.
I'm hoping that the code above is explains what I am trying to achieve, but do let know if further clarity is required.
Any help with this would be much appreciated. Thanks in advance.
I am using XML configuration, where I can map even protected or private members. So, surprising for me is that you are not receiving any Exception. Because your Collection does not have any setter (public nor protected). I would expect something like this:
NHibernate.PropertyNotFoundException: {"Could not find a setter for property 'Permissions' in class 'Person'"}
But maybe fluent is able to translate your mapping from Property to field.
I tried to test your code with a public setter or field (both shown below) and it worked. there is my snippet of xml mapping:
<!-- public or protected setter -->
<bag name="Permissions" inverse="false" lazy="true" table="PresonHasPermission" cascade="all">
<key column="PersonId" />
<element type="Permissions" column="PermissionId" />
</bag>
<!-- accessing the field -->
<bag name="permissions" inverse="false" lazy="true" table="PresonHasPermission" cascade="all"
access="field" >
<key column="PersonId" />
<element type="Permissions" column="PermissionId" />
</bag>
(Leaving your class definition unchanged when mapping to field)

Foreign Key Constraint is preventing NHibernate from saving child record

I have two tables:
SupportTicket
SupportTicketID
SupportTicketDate
SupportTicketNote
SupportTicketNoteID
SupportTicketNoteDate
SupportTicketID
With a foreign key constraint so I don't have any unassociated Notes...in sql that constraint is working properly.
On my SupportTicket class I have an IList SupportTicketNotes property and have it mapped as a bag (probably really should be a set but that's not important at the moment). The load works just fine. The problem is if I new up a SupportTicket, new up a SupportTicketNote, add the note to the ticket and save the ticket. NHibernate is inserting the SupportTicket, then inserting the SupportTicketNote with a SupportTicketID of zero which blows up of course because of the FK constraint. If I delete the constraint it will insert with the SupportTicketID of zero and then go back and do an update on the SupportTicketNote with the proper ID value...but that seems....wrong. Is there anything I might be doing in the mapping that is causing that?
UPDATED to include Many to One mapping on child object
Here's my current mapping for SupportTicket:
<bag name="_supportTicketNotes" table="SupportTicketNotes" access="field" cascade="save-update" inverse="true" >
<key column="SupportTicketID" foreign-key="FK_SupportTicketNotes_supporttickets" ></key>
<one-to-many class="NhibernateSample.DomainModel.SupportTicketNote, NhibernateSample.DomainModel" />
</bag>
Here is my mapping for SupportTicketNote (note my SupportTicketNote class has both the SupportTicketID and SupportTicket object properties):
<many-to-one name="SupportTicket" class="NhibernateSample.DomainModel.SupportTicket, NhibernateSample.DomainModel" column="SupportTicketId" cascade="all"/>
I haven't seen your full mapping, but the first thing that pops into my head is this section from the documentation:
Very Important Note: If the <key>
column of a <one-to-many> association
is declared NOT NULL, NHibernate may
cause constraint violations when it
creates or updates the association. To
prevent this problem, you must use a
bidirectional association with the
many valued end (the set or bag)
marked as inverse="true". See the
discussion of bidirectional
associations later in this chapter.
How have you mapped the parent SupportTicket property on SupportTicketNote? Are you setting the SupportTicket property when you add a SupportTicketNote to the collection? I almost always follow this pattern:
public class SupportTicket
{
private IEnumerable<SupportTicketNote> _notes = new List<SupportTicketNote>();
public IEnumerable<SupportTicketNote> Notes
{
get { return _notes; }
}
public void AddNote(SupportTicketNote note)
{
note.SupportTicket = this;
_notes.Add(note)
}
public void RemoveNote(SupportTicketNote note)
{
note.SupportTicket = null;
_notes.Remove(note)
}
}
Edited to add:
Your mapping for SupportTicketNote looks wrong. It should be many-to-one to SupportTicket and you shouldn't be mapping SupportTicketId at all. I've been using Fluent NHibernate for a while but I think the XML mapping should look like:
<many-to-one name="SupportTicket"
class="NhibernateSample.DomainModel.SupportTicket, NhibernateSample.DomainModel"
column="SupportTicketId" cascade="all"/>
You'll need to write your function in such a way that the persistance of the New SupportTicket happens prior to you adding the SupportTicketNote
e.g.
SupportTicket st = new SupportTicket();
SupportTicketNote stn = new SupportTicketNote();
///Code to set properties on both objects
st.Save();
st.SupportTicketNotes.Add(stn);
st.Save();

NHibernate: Map same class to multiple tables depending on parent

I have a model where multiple classes have a list of value types:
class Foo { public List<ValType> Vals; }
class Bar { public List<ValType> Vals; }
Foo and Bar are unrelated apart from that they both contain these vals. The rules for adding, removing, etc. the ValTypes are different for each class. I'd like to keep this design in my code.
There are times when I want to copy some Vals from a Foo to a Bar, for example. In the database, each ValType has its own table, to keep it small, light (it just has the parent ID + 2 fields), and allow integrity checks. I know NHibernate says I should keep my objects as granular as the database, but that just makes my code uglier.
The best I've thought of so far is to make separate subclasses of ValType, one for each parent. Then I can map those at that level. Then, I'll hook up add and remove logic to auto-convert between the right subclasses, and actually store them in a private list that has the right subclass type. But this seemed a bit convoluted.
How can I map this in NHibernate (Fluent NHibernate if possible)?
Please let me know if this is a duplicate -- I'm not quite sure how to search this.
At database level a solution would be to have:
Val(Id)
Bar(Id)
BarToVal(IdBar, IdVal)
FooToVal(IdFoo, IdVal)
I am not very sure how would these be mapped. Maybe something like:
// BarMap:
HasManyToMany(x => x.Vals).WithTableName("BarToVal");
// FooMap:
HasManyToMany(x => x.Vals).WithTableName("FooToVal");
Hope it's making sense...
You can find an example on the Google Code page for Fluent NHibernate.
Model
public class Customer
{
public string Name { get; set; }
public string Address { get; set; }
}
Schema
table Customer (
Id int primary key
Name varchar(100)
)
table CustomerAddress (
CustomerID int,
Address varchar(100)
)
Mapping
public class CustomerMap : ClassMap<Customer>
{
public CustomerMap()
{
Id(x => x.Id);
Map(x => x.Name);
WithTable("CustomerAddress", m =>
{
m.Map(x => x.Address);
});
}
}
In this example, an entity is split across two tables in the database. These tables are joined by a one-to-one on their keys. Using the WithTable feature, you can tell NHibernate to treat these two tables as one entity.

Fluent NHibernate question

Let's say you have two tables, "Users" and "UserRoles". Here's how the two tables are structured (table - columns):
Users - UserID (int)
UserRoles - UserID (int), Role (string)
What I want is for my "User" class in my domain to have an IList of roles. How do I construct my Fluent NHibernate mapping to achieve this?
What you're looking for is a of a set of elements, which in standard hbm mapping is:
<set name="Roles" table="UserRoles">
<key column="UserID" />
<element column="Role" />
</set>
For Fluent NHibernate you can map this like so:
HasMany<string>(x => x.Roles)
.AsElement("Role");
You may need to also specify the key name using WithKeyColumn(string).
FWIW this has change minorly of present day. The current mapping is
HasMany<string>(x => x.Roles)
.Element("Role");
I beleive it would be
public User()
{
Id(x => x.UserID);
HasMany<UserRoles>(x => x.UserRoles).AsBag();
}
You'll also have to make sure you map your UserRoles class as well
This also worked:
HasMany<Role>(u => u.Roles)
.WithTableName("UserRoles")
.Component(role => role.Map(r => r.Name))
.AsList();
You don't need to map Role or UserRoles.
Make sure Role implements IEquatable < Role > ;.