My goal is to use NHibernate schema generation along with Fluent NHibernate's automapper to generate my database. I'm having trouble with what I'll call "unidirectional many-to-many relationships."
Many of my entities have localized resources. A single class might look like this:
public class Something {
public virtual int Id {get; private set;}
public virtual Resource Title {get;set;}
public virtual Resource Description {get;set;}
public virtual IList<Resource> Bullets {get;set;}
}
The Resource class doesn't have any references back; these are entirely unidirectional.
public class Resource {
public virtual int Id {get; private set;}
public virtual IList<LocalizedResource> LocalizedResources {get;set;}
// etc.
}
public class LocalizedResource { //
public virtual int Id {get; private set; }
public virtual string CultureCode {get;set;}
public virtual string Value {get;set;}
public virtual Resource Resource {get;set;}
}
Without the IList<Resource>, everything is generated as I'd want -- Resource ID's are in the Title and Description fields. When I add in the IList though, NHibernate adds the field something_id to the Resource table. I understand why it does this, but in this situation it's not a sustainable approach.
What I want is to create a junction table for the bullets. Something like:
CREATE TABLE SomethingBullet (
Id int NOT NULL PRIMARY KEY IDENTITY(1,1),
Something_Id int NOT NULL,
Resource_Id int NOT NULL
)
This way when I add the other twenty-odd entities into the database I won't end up with a ridiculously wide and sparse Resource table.
How do I instruct the Automapper to treat all IList<Resource> properties this way?
Every many-to-many is in fact composed with one-to-many's in object model. If your relationship doesn't need to be bidirectional, just don't map the second side. The mapping on your mapped side is not affected at all:
HasManyToMany(x => x.Bullets).AsSet();
In this case, NHibernate already knows that it needs to generate the intermediate table.
See also this article for many-to-many tips.
:)
The only way I found to make this work with automapping is by constructing your own custom automapping step and replacing the "native" HasManyToManyStep. It's either that or an override, I'm afraid.
I lifted mine off of Samer Abu Rabie, posted here.
The good news is that Samer's code, so far, seems to work flawlessly with my conventions and whatnots, so, once it was in place, it was completely transparent to everything else in my code.
The bad news is that it costs you the ability to have unidirectional one-to-many relationships, as Samer's code assumes that all x-to-many unidirectional relationships are many-to-many. Depending on your model, this may or may not be a good thing.
Presumably, you could code up a different implementation of ShouldMap that would distinguish between what you want to be many-to-many and what you want to be one-to-many, and everything would then work again. Do note that that would require having two custom steps to replace the native HasManyToManyStep, although, again, Samer's code is a good starting point.
Let us know how it goes. :)
Cheers,
J.
Related
I'm trying to setup my domain models around the DDD principles. Right now I have the following class:
class Customer : AggregateRoot
{
public string CustomerReference {get;set;}
public string CustomerName {get;set;}
public string List<Adult> Adults {get;set;}
public string List<Child> Children {get;set;}
}
Creating a Customer is the essence of the application, so I made that class an AggregateRoot. Because a lot of
times the end user will want to find a customer by its CustomerReference key.
But then again, sometimes the end user wants to search by the name of a Child, to find out the Customer info. Or even sometimes
by the name of an Adult.
I'm not sure if that means that I should make the Child and Adult classes also an AggregateRoot? Or should I always
start searching from the Customer AggregateRoot if I want to search by a Child or Adult name?
No - aggregate root members are only accessible via the aggregate root.
however, If you are wanting to manipulate Adult/Child entities on their own, it is likely you don't need the full Adult and Child entities as part of the customer root. If this is the case replace those collections of entities with collections of Id's and rely on the fully entities to be provided to any functions that require their attributes.
class Customer : AggregateRoot
{
public string CustomerReference {get; private set;}
public string CustomerName {get; private set;}
public string IEnrumerable<AdultId> Adults {get; private set;}
public string IEnrumerable<ChildId> Children {get; private set;}
public void RegisterAnAdult(Adult adult) {...}
public void RegisterAChild(Child child) {...}
}
I emphasised If because this looks a little bit off unless your system is huge and Adult and Child can belong to multiple customers. (How do you handle when an child grows up to transition to an adult?)
As #mgonzalezbaile said, don't model your domain based on queries - searching is a whole different thing - model it on business behavior. (For more info start with [http://www.zankavtaskin.com/2016/06/applied-domain-driven-design-ddd-part-7.html])
Finally, in your example the properties are publicly set-able, if this is on purpose then it might be worth stepping back and re-reading the literature on DDD a few more times, public settable properties potentially allow your entity to move to an invalid state, something that DDD tries to avoid.
I'm designing a fairly complex hosted web app that needs to support multiple "Teams" that are effectively isolated from each other. For example, the tables People, Areas, Reports, etc. will have intermingled data populated by the teams at Corporation A, B, C, and on down the line, and the user from Corporation A has logged in, he should only ever see data relevant to corporation A. My plan is to create a relationship between Team and (nearly) every other type and to use a repository to access all those other types, and always query where TeamId matches the TeamId of the person logged in.
So since I want to have
[ForeignKey("Team")]
public int TeamId { get; set; }
public virtual Team Team { get; set; }
on almost every class, I was thinking it might be nice to put those in an abstract class and inherit those properties:
public abstract class OfTeam {
[ForeignKey("Team")]
public int TeamId { get; set; }
public virtual Team Team { get; set; }
}
public class Person : OfTeam {
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
But, I realize this isn't truly what inheritance is about. So I'd like to know
Will this even work?
Is it a terrible idea?
I misunderstood at first and though you were inheriting team, which would have been a bad idea.
If you ever query db.OfTeam then it will union together every single table that inherits from it, which will perform terribly. Scroll down to see the SQL produced here:
http://weblogs.asp.net/manavi/archive/2011/01/03/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and-choosing-strategy-guidelines.aspx
Otherwise the actual DB structure should be identical to if you simply put TeamId/Team on all of those classes directly.
I personally wouldn't do this because it adds little value and could potentially cause headaches down the road.
Instead you could just have an IOfTeam interface on all those classes if there is a need to interact with them in a generic manner for some reason.
As a side note I've done something similar and usually cache TeamId somewhere easily accessible, such that I can anywhere do CurrentIdentity.TeamId and pass it to a query. This allows methods on repository pattern like GetPeople to apply a where criteria with that filter before returning the IQueryable.
In NHibernate manual I have found mapping like this:
<bag name="Sizes" table="SIZES" order-by="SIZE ASC">
<key column="OWNER"/>
<element column="SIZE" type="Int32"/>
</bag>
I can't help wondering why would anyone want to do something like this? Is there something better about mapping plain integers than creating an entity corresponding to a given integer (Size entity in this scenario) and creating true one-to-many relationship?
The requirements of your business domain that your application operates in will dictate whether you should have a list of ints (a collection of value types), or a list of entities. If there's a good use case for a IList<int> then by all means go for it, and let NHibernate map this association accordingly. Otherwise just remove it.
However, removing it because it seems unfamiliar to you, isn't a valid reason.
I use this a lot in my domain models. Right now I have a lot of 'Twitter Applications' that index tweets based on search 'Keywords', so I have mapped it like this:
public class TwitterApplication
{
public virtual int Id { get; set; }
public virtual string ApplicationName { get; set; }
// other properties (snip)
public virtual ISet<string> Keywords { get; set; }
}
I use this mapping because I know that:
The number of Keywords will be small
(about 4 - 6)
I'm not interested in storing
Keyword DateAdded etc.
I'm not going to be doing Paging or
Querying on the Keywords, just
retrieve them all at the same time,
or not at all
On this basis, I decided mapping it as a collection of strings was appropriate.
The question is not if you want to map it like this, the question is, if you need a list of ints in your model.
When you have a list of ints in your model, then you want to map it like this. You don't want to write complex code in your model, just because of the mapping.
So, do you think it is useful to have a list of ints in a class? Or a list of Guids, enums, doubles?
class Graph
{
IList<double> Values { get; private set; }
}
Doesn't it make sense to you?
I know in NHibernate you can have inheritance mappings, and I know you can have table-per-class, table-per-subclass and table-per-concrete-class but they don't quite fit the scenario I have.
Basically what I want is to be able to have a base class called product that looks like this:
public class BaseProduct
{
public virtual int ProductId {get;set;}
public virtual string ProductName {get;set;}
}
which maps directly to a product table.
Then I want to have a Product class which inherits from BaseProduct like this:
public class Product : BaseProduct
{
public virtual IList<Category> Categories {get;set;}
}
The thing is that the Product class should still map to the product table, the only difference being that this implementation has a list of Categories attached.
Without going into the technical reasons for why I need to do this, I would like to know if it's at all possible?
From your question and comment, I get that you want «Single Table Inheritance» [PoEAA, Fowler], but don't have the luxury of being able to add the needed discriminator to the table.
I've never run into this situation myself, but try to add a discriminator to your mapping which is a calculated value/derived field that uses sql to find out if there are foreign keys from Category (won't work for Products with empty Category collections though).
If your scenario is a read-only one, and you can add views to the DB, it's an option to map to a Product view with the discriminator calculated as stated above.
You are looking for a table perclass you need to set a discriminator-value
NHDoc for inheritance
Do you have other classes that inherit from BaseProduct? If not, you can just map the Product class only.
Possibly a dumb question but I have a number of entities all inheriting from a base entity. The base entity does not have a table in the database. Each entity has its own table and the table definition is exactly the same. Extremely simplified example of the code is below.
public abstract class BaseEntity
{
public virtual string someProperty {get; set;}
}
public class Entity1 : BaseEntity{}
public class Entity2 : BaseEntity{}
public class CompletelyDifferentEntity
{
public virtual IList<BaseEntity> {get; set;}
}
I created the mappings for the entities. In my other domain classes if I reference the concrete classes everything works fine but if I change my other classes to reference BaseEntity instead I get a mapping Exception because the BaseEntity is not mapped. Is this something where I should use a subclass discriminator? I guess I'm not seeing the correct way to do this if the base doesn't have an associated table and the subclasses don't have a specific column that is different between the table definitions.
You have to use one of three available inheritance mappings strategies. From your description, you should consider using table-per-concrete-class mapping, or change your db scheme.
You can find more information about pros and cons of strategies here: https://www.hibernate.org/hib_docs/nhibernate/html/inheritance.html.