In a studied domain, a Car may have many Tires and according to DDD concepts, Car is an aggregate root while Tire is a Value Object. '
Consider the following model:
class Car
{
public int Id {get;set;}
public virtual ICollection<Tire> Tires {get;set;}
}
[ComplexType]
class Tier
{
public string Manufacturer {get;set;}
public int Diameter {get;set;}
}
I'm afraid EF 6.0 + cannot implement this model. Am I right? Any way to implement Collection of Value Objects?
Complex types, according to MSDN documentation, cannot participate in associations and cannot contain navigation properties so this is not the right way.
With EF the only way is to have 2 tables (with an Id on the Tires table). You can also hide Id of the Tires table, you can insert a unique index on the foreign key of the Cars table but when you check if two tires are equal you need to check if both properties are equal.
This is a common issue with normalized persistence (which includes the SQL server which you access through EF). Entity framework makes it more difficult by not allowing you to have a protected key though.
One way is to have a Tires table which has an id, which will form part of a foreign key relationship with car. However, the idea of a unique key violates the fact that value objects should not rely on id's and should be compared by value. Being diligent, overriding Equals, and only comparing by value will allow you work with this solution; it does not matter if the actual objects are different as long as the equality comparison would return true if two tires matched. It is not pretty, I agree, but with EF it seems to be the only solution. If I am wrong, please someone correct me. If you go this route, remember to map your domain data to your DTO's in a way that the Id is removed. That way you keep the fact that tires have an id isolated.
Another solution is to serialize the tires using Json before being sent to SQL db (and then deserialize it back on read), but that is not something that I would personally suggest if you need to query on information in the tires (for example give me all cars that use this kind of tyre).
PS: Vaughn Vernon discusses this particular issue with Hibernate for Java in this book: http://www.amazon.co.uk/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577 Please read, it will solve a lot of the issues or questions you may have on the subject.
Related
I am fairly new to Entity Framework and I've spend the last 4 hours day trying to make a (to me seemingly) simple relation to work.
I have three classes: Person, House, Garage
A Person can have none or multiple (0..n) Houses and Garages
A House can have (0..1) a Garage and must only belong to one Person
A Garage can therefore also have (0..1) a House and must only belong to one Person
There are Garages with no Houses and Houses with no Garages
At no point can there be a Garage or House without a related Person (that's easy, I think I got that one)
By now I've read like 10 different documentations that all make matters only more confusing to me. I've tried solving it using annotations but it seems that I also have to incorporate this fluent api stuff.
The furthest I've gotten is to have Houses and Garages associated to a Person, but not to eachother. Now I've been stuck having to define the principle end of a relationship, which I don't even understand what it's supposed to do.
Right now I get
Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values.
from trying to solve a barrage of different errors.
I've been implementing relations like these for ages in PHP, manually, by writing all my own queries. This is the first time I'm doing database stuff in a bigger framework that is supposed to make things easier, but so far I'd have had more success in filling the objects myself from a DatabaseReader.
From my logical point of view the relation between the three Classes/Tables should be really simple yet I can't find examples of similar relations or get it to just work.
So my questions are:
Is a zero-or-one to zero-or-one relation really that special that it's so hard to design in code first?
Wouldn't the Garage table not need a foreign key to the House table, because it's possible to find the corresponding House by filtering the House table for the GarageId? I've tried implementing a lookup of the House in code but noticed that it breaks a lot of LINQ because it's not a database property anymore.
I've tried Annotations and Fluent API, all the top examples of 0..1 to 0..1 (or really, any other) relations from SO, tried swapping fields in the modelBuilder because it didn't look right in the DB... until reaching a point where the DB looks kinda okay but the code still refuses to work. What else can I try?
Maybe I've been doing all the DB stuff wrong all my life and having relations like these are unhealthy for everyone involved. In that case, what alternatives would you suggest that I try to replicate the Person-House-Garage relation described above? Are there any helper classes that I can shove between Houses and Garages to get it to work?
I have prepared a demo project: https://github.com/Zaphox/DatabaseTest
It contains the three classes, context and a test of the relations that should successfully complete (but doesn't).
Thanks for any and all help and hints that lead to the solution to this problem!
Z.
Update 1
After trying all suggestions I noticed that any circular relation causes errors in EF and it seems that it's just not possible to create references like these, even 0..1 to 0..1 self references do not seem to work.
I have however implemented a hack that at least lets me work, but it's horrible and I would love for someone to tell me that there's a better way.
Only Houses have references to Garages, not vice versa
To get a House belonging to a Garage a separate query is required (db.Buildings.OfType<House>().Where(h => h.Garage.Id == myGarage.Id).First())
Also I thought about adding a NotMapped House field in the Garage which does a lookup for the house by itself but it interferes with other queries, so that's not a valid option either.
What annoys me most is that there are a lot of articles about self-references and the likes, but only for 1 to n relations. Any attempt to make a 1 to 1, or 0..1 to 0..1 relation, always fails with EF not being able to figure out the "order".
The thing is that EF thinks it has to make put a GarageId FK in the House table, and a HouseId FK in the Garage table, which is nonsense. I only need a GarageId in the House table, which can used as a backwards reference. I can implement this code-wise but it's not compatible to EF queries and usually interferes with other running queries because you can't run two queries at once.
The demo project on GitHub is updated with the current version, which kinda works but requires a lot of additional querying every time I want to find the House belonging to a Garage.
Apparently the problem is the relationship between House and Garage.
I only need a GarageId in the House table, which can used as a backwards reference.
In fact this is what happens by default when you put only Garage navigation property on House class (with the only difference that the FK column name is Garage_Id). This is called unidirectional association. With such setup EF considers House to be the dependent, Garage to be the principal and both to be optional. The important part is that FK column is created in dependent table.
So this is what you have currently in your test project and it works. The problem arises when you make the association bidirectional by adding House property to Garage class:
public class House
{
public int Id { get; set; }
public Garage Garage { get; set; }
public string Style { get; set; }
}
public class Garage
{
public int Id { get; set; }
public House House { get; set; }
public int Size { get; set; }
}
In this case EF has no enough information what is your intention, so you need to provide that information. Remember that you want GarageId FK in House table, so here is the corresponding Fluent configuration that you need to add (the Map part is optional - if you skip it, the FK column will be called Garage_Id as in your current project):
modelBuilder.Entity<House>()
.HasOptional(e => e.Garage)
.WithOptionalDependent(e => e.House)
.Map(m => m.MapKey("GarageId"));
and everything will work as expected.
Entity Framework doesn't like relationships where there is no clear principal. In this case as either entity can exist without the other, neither is dependent on the other.
I would suggest redesigning your model so that you have an abstract class Building which House and Garage both derive from. You can then link your Person to a Building, and in the concrete types 'House' and Garage have a link to a Building for the association.
Example:
public abstract class Building
{
public Person Person { Get; Set; }
public Building Building { Get; Set; }
}
public class House : Building
{
// Other House properties
}
public class Garage : Building
{
// Other Garage properties
}
Then in the business logic you can enforce that the associated building cannot be of the same type with something like this.GetType() != Building.GetType()
User always has one Wallet. One Wallet belongs always to one User.
Since I want to separate money wallet related properties I was create Wallet object and to be able to track money transactions, ... I created
public Wallet : Entity<int>
{
public double Amont {get; set;}
public IList<MoneyTrans> Transactions {get; set;}
}
Since this is obviously one to one relationship is it ok to map using one to one relationship?
Is one to one bad strategy?
I had to append answer, with opposite point of view. Do not use one-to-one mapping. At least with NHibernate.
I am not talking about the conceptual domain driven design. Just about my experience with DB design and NHibernate usage.
1) one-to-one - Rigid DB design
First of all the desing with shared primary keys (except of inheritance) could lead to many issues later, when the Business requirements are changed.
The typical scenario, very similar to example 23.2. Author/Work, where Author is mapped one-to-one to Person. Therefore, the id (primary key) of the Author comes from a Person (id). Sooner or later, Business will come and ask could we have to person mapped to Author (see Lars Kepler example)
What I am trying to say here is: Chapter 24. Best Practices (let me cite one point)
Declare identifier properties on persistent classes.
NHibernate makes identifier properties optional. There are all sorts of reasons why you should use them. We recommend that identifiers be 'synthetic' (generated, with no business meaning) and of a non-primitive type. For maximum flexibility, use Int64 or String.
As mentioned here (and from my experience), it is very benefitial to have all entities with their own surrogated primary keys. The changes in relations coming later - will effect just references (on top of surrogated keys), not the table/entities themselves.
2) one-to-one with NHibernate cannot be lazy
In fact this reason is the one, why (despite of the fact I tried few times) currently do not use the one-to-one at all. The one-to-one is not supporting lazy loading. Search for more info but nice explanation could be found here:
Ayende NHibernate one-to-one (a cite)
In other words, one-to-one cannot be lazily loaded, which is one of the reasons why it is recommended to use two many-to-one instead.
Some explanations on lazy loading (one-to-one)
As mentioned in one of the links in comments below the question (cite)
You can either include all those attributes as columns into your entity table - but in that case, lots of columns would end up empty for a significant number of the entries.
Or: you can put those "optional" attributes into a separate table, set up a 1:1 (or rather: 0:1) relationship with the base entity table,
Well, with NHiberante you won't get so much improvement. This suggestion is wrong. Lazy loading of one-to-one isn't supported...
SUMMARY:
That's why I would strongly suggest: use many-to-one or one-to-many where possible. You'll gain more...
No it's fine. It's not just about relationships but object orientation. Fundamentaly a Wallet is not an unseverable part of a Person.
Looking beyond that, whilst the wallet might belong to a specific 'John' now, 'James' might be given it as a present. From the data perspective it's much better to just change the WalletId fields of John and James of which one may be null (although not in your case) if they don't have a wallet.
I came to a conclusion that it is impossible to properly implement GetHashCode() for an NHibernate entity with an identity column. The only working solution I found is to return a constant. See below for explanation.
This, obviously, is terrible: all dictionary searches effectively become linear. Am I wrong? Is there a workaround I missed?
Explanation
Let's suppose we have an Order entity that refers to one or more Product entities like this:
class Product
{
public virtual int Id { get; set; } // auto; assigned by the database upon insertion
public virtual string Name { get; set; }
public virtual Order Order { get; set; } // foreign key into the Orders table
}
"Id" is what is called an IDENTITY column in SQL Server terms: an integer key that is automatically generated by the database when the record is inserted.
Now, what options do I have for implementing Product.GetHashCode()? I can base it on
Id value
Name value
Identity of the product object (default behavior)
Each of these ideas does not work. If I base my hash code on Id, it will change when the object is inserted into a database. The following was experimentally shown to break, at least in the presence of NHibernate.SetForNet4:
/* add product to order */
var product = new Product { Name = "Sushi" }; // Id is zero
order.Products.Add(product); // GetHashCode() is calculated based on Id of zero
session.SaveOrUpdate(order);
// product.Id is now changed to an automatically generated value from DB
// product.GetHashCode() value changes accordingly
// order.Products collection does not like it; it assumes GetHashCode() does not change
bool isAdded = order.Products.Contains(product);
// isAdded is false;
// the collection is looking up the product by its new hash code and not finding it
Basing GetHashCode() on the object identity (i.e. leaving Product with default implementation) does not work well either, it was covered on StackOverflow before. Basing GetHashCode() on Name is obviously not a good idea if Name is mutable.
So, what is left? The only thing that worked for me was
class Product
{
...
override public GetHashCode() { return 42; }
}
Thanks for reading through this long quesiton.
Do you have any ideas on how to make it better?
PS. Please keep in mind that this is an NHibernate question, not collections question. The collection type and the order of operations are not arbitrary. They are tied to the way NHibernate works. For instance, I cannot simply make Order.Products to be something like IList. It will have important implications such as requiring an index/order column, etc.
I would base the hashcode (and equality, obviously) on the Id, that's the right thing to do. Your problem stems from the fact that you modify Id while the object is in the Dictionary. Objects should be immutable in terms of hashcode and equality while they are inside a dictionary or hashset.
You have two options -
Don't populate dictionaries or hashsets before storing items in DB
Before saving an object to the DB, remove it from the dictionaries. Save it to the DB and then add it again to the dictionary.
Update
The problem can also be solved by using others mappings
You can use a bag mapping - it will be mapped to an IList and should work OK with you. No need to use HashSets or Dictionaries.
If the DB schema is under your control, you may wish to consider adding an index column and making the relation ordered. This will again be mapped to an IList but will have a List mapping.
There are differences in performance, depending on your mappings and scenarios (see http://nhibernate.info/doc/nh/en/#performance-collections-mostefficientupdate)
I know that this is a repeated question and I know that this is not possible if there are additional properties in the "in the middle" table.
I had an idea how to get the effect of an m:N relationship instead of an 1:n-n-1, but I'd like to hear some other thoughts.
If I have three entities, A, B, and AB where AB makes the A:B relation possible and it has additional properties.
Using Databasefirst approach, I thought to make a partial class of A and B.
public partial Class A
{
public IEnumerable<EntityObject> Bs
{
get
{
return this.Select(p=>p.AB.B);
}
set { //... }
}
}
Could something like this be possible.
Just doodling in my head. I am currently on vacation and have no computer, so this is not tested but just written on my cell phone.
I see that this could be a problem after context disposing or detaching, also with including in an eager loading approach.
Any thoughts?
If you are already treating AB as a distinct entity, then to get all B from A all you need is something like this:
public partial class A
{
public IQueryable<B> Bs {
get { return this.ABs.AsQueryable().Select(ab => ab.B).Distinct(); }
}
}
I'm not sure how well this will perform, as compared to a built-in Many-To-Many supported by EF (without any payload), but it will give you what you are asking.
If technically possible or not, expressing such a relationship with "additional properties in the in the middle table" as many-to-many relationship is just wrong because it hides that the "middle table" has a business meaning and therefore must be an entity on its own.
A somewhat classical example for such a model are RawMaterial and Product: A RawMaterial can be used in multiple Products and a Product can be made of multiple RawMaterials. The entity in between - maybe called RecipePart - contains a Quantity how many pieces of a given RawMaterial are used in a given Product.
If you have for example the product ChocolateBar and work with its relation to raw materials you will deal with a recipe that says a ChocolateBar has 60 units of Chocolate and 40 units of Milk, i.e. ChocolateBar has a collection of RecipeParts and every RecipePart describes the quantity and refers to the related RawMaterial. A ChocolateBar does not have a direct collection of RawMaterials in this business model.
For a particular query (maybe some statistics) you might be only interested in its raw materials - a chocolate bar is made if chocolate and milk, no matter how many units - but that is a special query in your business model and kind of an aggregation that ignores some pieces of the full detailed model information. This is what your helper property this.Select(p=>p.AB.B); does: It does not express the full relationship but is a specialized query that says: Give me only the RawMaterials for this Product, I don't want to know each quantity.
Characteristically you have left the property setter set { //... } a stub. When adding or changing entities it becomes obvious that the relationship cannot be many-to-many. It is not possible to assign only a list of RawMaterials to a Product. You must add the information how many units of each RawMaterial to get a valid Product model which means that Product must be related to the "middle entity" RecipePart.
Several sources state that NHibernate can not use identity with table per concrete class and union-subclasses. Is this true, and what is the exact reason behind this ?
It's simple. The POID must be unique across all instances of a root entity type.
Consider the following example:
abstract class Vehicle { ... }
class Car : Vehicle { ... }
class Truck : Vehicle { ... }
If you were to retrieve a Vehicle whose concrete type you don't know:
var carOrTruck = session.Get<Vehicle>(vehicleId);
...and there were both a Car and a Truck with that Id (which is possible with identity), which one would NHibernate return? (there are more complex cases, but this illustrates one possible issue)
Therefore, for table-per-concrete-class (a pretty bad strategy if you ask me), NHibernate needs a generator that guarantees uniqueness across subclasses.
Why do you say so? I think I had several scenarios like that. Also this blog entry states the same.
To sum up comments below:
as in the example that Ayende has, if you query for all root types (so "Select Party") you can get duplicates for ID. That fact along with UNION characteristic (returns only distinct records) could give you unexpected results (missing records). That's why you cannot use identity but rather hilo which allows nhibernate to avoid duplicates.