How to Implement Cascading Object Properties in C# - c#

I have been tasked with doing the data mapping for a C# api, and it is one which features some more complex data relationships than I typically have had experience with (I have worked with foreign keys without data cascades, and have not validated data according to subclass before).
I am unsure of how to correctly institute the data mapping I have been tasked with - I could surely come up with something but I would rather not end up committing anti-patterns to the repo.
There is a parent class, let's say, Treat. All treats must have certain ingredients:
public class Treat
{
public ICollection<Ingredient> Ingredients { get; }
// Other members omitted
}
public class Ingredient
{
public Ingredient() { }
// Other members omitted
}
public class Sugar : Ingredient
{
public Sugar() { }
// Other members omitted
}
So let's say Treats are allowed to have (but don't have to) Sugar and Artificial Flavours only as ingredients. We define more ingredients for specific treats by referring to subclasses:
public class Chocolate : Treat
{
// Implementation omitted
}
Chocolate, let's say, can also have Cocoa : Ingredient and Flour : Ingredient.
How can I implement this mapping? I was going to store everything in columns of the one table and validate in the api endpoint controllers originally but I have been asked to reflect the validation rules in the class structure.

Your example code only contains a N:M or Many to Many relationship. Every Treat (N) can have several Ingredients (M). But each ingredient (M) can also be used by several Treats (N). Those are very common, very standart problems. They can not be resolved really, only disolved into two smaler Problems.
On the DB side N:M Relationships are usually disolved into a N:1 and 1:N relationship, using a middle table (TreatIngridients). A table consisting of nothing but a Primary Key and two Foreign Keys. I am not sure how to implement a N:M on the class side, but it is a exceedingly common problem of code first. So I quickly found one link to EF:
https://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
Apparently both Clases will contain a List of their counterparts. This setup of cross references pains every programmer part of my brain (I hope I never get to do a OUTER JOIN on that. Keeping both lists in synch would be a nightmare). However it would be easily build from a Databse. You either build your Instances in Memory from the Ignredient side or the Treat side. The other will be mostly static data (with ingredients being propably usually the other side)

Related

Should I have duplicate class properties or create an extra database table?

I'm trying to come up with a data model to represent a simple money transaction system.
I have one class to represent a Transaction, and another class to represent a TransactionRecurrence.
Both classes will need properties for an Id, Amount, Type (Withdrawal/Deposit), and a Note of some sort. The Transaction will also hold a TransactionDate, while the TransactionRecurrence will hold some sort of data to represent the recurrence (10th of every month etc.).
My question is: For the properties that both classes will share should I just duplicate the properties in both classes (which would go against DRY principle), or should I create a new class, say, TransactionInfo that holds the four properties then add a property with that type to the two other classes (which would require a new DB table and foreign key references/SQL joins that would slow down the queries)?
Edit: For example users will each have a collection of Transactions (which are one-time transactions) and a separate collection of TransactionRecurrences both which they create on the client via a web api. These are stored in the database in separate tables. Then the user can request the transactions through the api. The Transactions can just be added to a collection directly, but the TransactionRecurrences will need to be used to generate more Transaction objects based upon a date range passed in with the request before being added to the collection. The collection is then serialized and sent to the requester.
Why not have a abstract base class or interface holding those common properties and have your concrete classes implement or inherit that interface or base class. That way you are not duplicating the properties anymore.
Moreover, explain what you are trying to achieve actually and provide better example. So that someone may come up with a better approach.
If every transaction should have recurring facility then you can consider using Composition like below
public class TransactionRecurrence
{
public int DurationPerMonth { get; set; }
}
public class Transaction
{
public TransactionRecurrence _transref;
public Transaction(TransactionRecurrence transref)
{
_transref = transref;
}
//other properties
}

Issue with many-to-many relationship + TPH inhertitance in Entity Framework 6

I am running into an issue with EF6, though I'm fairly sure that this applies to previous versions that support this type of mapping. I fear I know the answer to the question at hand, but I hope that I am doing something wrong, or there is a better workaround than what I present here. All classes are gutted for clarity.
So I have
public abstract class SoftwareFirmware
{
public long Id { get; private set; }
public ICollection<DeviceType> DeviceTypes { get; private set; }
public SoftwareFirmware()
{
DeviceTypes=new HashSet<DeviceType>();
}
}
and
public class DeviceType
{
public long Id { get; set; }
public virtual ICollection<Firmware> AvailableFirmwareVerions { get; private set; }
public virtual ICollection<Software> AvailableSoftwareVerions { get; private set; }
public DeviceType()
{
AvailableFirmwareVerions = new HashSet<Firmware>();
AvailableSoftwareVerions = new HashSet<Software>();
}
}
which as you can see have a many to many relationship defined. I've defined two classes which derive from SoftwareFirmware, the aptly named
public class Firmware : SoftwareFirmware {}
and
public class Software : SoftwareFirmware {}
I'm using Table Per Hierarchy inheritance, so Software and Firmware are stored in the same table with a discriminator column. Finally, I've mapped the relationships in the derived DbContext's OnModelCreating method with
modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableFirmwareVerions).WithMany(firmware=>firmware.DeviceTypes);
modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableSoftwareVerions).WithMany(sofware=>sofware.DeviceTypes);
The problem at hand is that Entity Framework does not seem to support inheritance with this mapping, as I receive the following when EF tries to generate the database:
DeviceTypes: FromRole: NavigationProperty 'DeviceTypes' is not valid.
Type 'Software' of FromRole
'DeviceType_AvailableSoftwareVerions_Target' in AssociationType
'DeviceType_AvailableSoftwareVerions' must exactly match with the type
'SoftwareFirmware' on which this NavigationProperty is declared on.
From this I gather that a type that inherits from SoftwareFirmware is not good enough for the NavigationProperty, it must be a SoftwareFirmware type. If I tear the DeviceType collection out of the SoftwareFirmware base class and duplicate it in each of the derived classes, things work, but that's certainly less than ideal.
So finally, my question is- is there another way to configure this so that I can keep my navigation property in my base class? If not, is there a cleaner workaround than what I've described?
UPDATE: so it would seem that SQL Server Management Studio did me wrong, as I had diagrammed out the database previously without the overloaded version of WithMany that takes an expression and it did not include the junction tables. It seems like SSMS doesn't play nice with schema changes in terms adding new diagramming even when the database has been dropped and recreated- it must be restarted. Major pain, but I digress...
As a last ditch effort, I reverted to the parameterless version of WithMany for the mappings, deleted and recreated the database by restarting the application, restarted SSMS, and lo! The junction tables were created. All I needed to do is add an Ignore for the base SoftwareFirmware class's DeviceTypes property and everything generated cleanly. So my FluentAPI mapping code looks like this:
modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableFirmwareVerions).WithMany();
modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableSoftwareVerions).WithMany();
modelBuilder.Entity<SoftwareFirmware>().Ignore(s => s.DeviceTypes);
which generates this schema- pretty much exactly the schema I wanted (ignore the extra properties):
However, since the parameterless call to WithMany only hooks up a navigation property on one side, updates to Software.DeviceTypes and Firmware.DeviceTypes aren't tracked by EF so I'm back where I started.
The issue is that you have a single SoftwareFirmware.DeviceTypes property but you are then trying to use it as part of two separate relationships. SoftwareFirmware.DeviceTypes can't be the inverse of both DeviceType.AvailableFirmwareVerions and DeviceType.AvailableSoftwareVerions.
What you're trying to model is a bit strange because you're kind of treating them as distinct relationships, but also not. There are two options here...
Option 1: It's two separate relationships
Remove SoftwareFirmware.DeviceTypes and add a DeviceTypes property on Firmware and Software.
This is actually what you are doing when you put Ignore on the SoftwareFirmware.DeviceTypes property and use the empty overload of WithMany - which is why it works. You're telling EF that there are two relationships (one Software -> DeviceType and the other Firmware -> DeviceType) and that there is no navigation property that points back the other way. Since you ignored SoftwareFirmware.DeviceTypes it's just not part of your model.
Option 2: It's one relationship
Remove the two navigation properties on DeviceType and replace them with a single navigation to the SoftwareFirmware base class. You can always add some façade properties that filter the contents to Software and Firmware (as shown below)
public class DeviceType
{
public long Id { get; set; }
public virtual ICollection<SoftwareFirmware> AvailableVerions { get; private set; }
public virtual IEnumerable<Firmware> AvailableFirmwareVerions
{
get
{
return this.AvailableVerions.OfType<Firmware>();
}
}
public virtual IEnumerable<Software> AvailableSoftwareVerions
{
get
{
return this.AvailableVerions.OfType<Software>();
}
}
public DeviceType()
{
AvailableVerions = new HashSet<SoftwareFirmware>();
}
}
This problem sounds familiar. (checking my email ...yep it was over a year ago!) I had someone send me a sample where a fluent api relationship was failing. They did not have a many to many but I think it's the same problem. I spent a long time looking at it and asked Rowan Miller (on the team) and he said that the fluent api can't comprehend the property coming from the base type.
i.e. the fluent API can't see the DEVICETYPE property when it's looking at AvailableSoftwareVerions or at AvailableFirmwareVersions. (I can't tell you WHY this is. You'd think it could find it via reflection but maybe it just wasn't designed with this scenario in mind.)
This still didn't make sense to me so he explained further (and I'll update his explanation with your types which was a little confusing since you have extra levels of inheritance and things are named a bit inconsistently ...but I
Conceptually the classes don’t really make sense, because a DeviceType
can have many Software(s) or Firmware(s)… but the inverse navigation property is
defined on SoftwareFirmware. So what happens when something that isn’t
a Firmware or Software has a DeviceType? It’s inverse is configured as > DeviceType.AvailableSoftwareVersions
but that can’t work. Even taking EF out of the picture the correct way
to model that is to have the Project property be on Report.
That was with EF5. If my memory is correct and it's the same problem, then maybe it hasn't changed for EF6. Perhaps we should look to see if there's an issue in there for solving this problem. However, his further explanation suggests that it's not a bug but a protection.
(I'm going to ping him to verify that I'm inferring the previous problem to this one correctly).
In that email, Rowan also suggested using getter logic instead of a navigation properties as a workaround.

Entity Framework Decorator Pattern

In my line of business we have Products. These products can be modified by a user by adding Modifications to them. Modifications can do things such as alter the price and alter properties of the Product. This, to me, seems to fit the Decorator pattern perfectly.
Now, envision a database in which Products exist in one table and Modifications exist in another table and the database is hooked up to my app through the Entity Framework. How would I go about getting the Product objects and the Modification objects to implement the same interface so that I could use them interchangeably?
For instance, the kind of things I would like to be able to do:
Given a Modification object, call .GetNumThings(), which would then return the number of things in the original object, plus or minus the number of things added by the modification.
This question may be stemming from a pretty serious lack of exposure to the nitty-gritty of EF (all of my experience so far has been pretty straight-forward LOB Silverlight apps), and if that's the case, please feel free to tell me to RTFM.
Thanks in advance!
Edit:
It would also be nice if, given a third table, linking a Products to Modifications (one-to-many) it could reconstruct the decorated object (I realize that this is likely way out of bound for the EF to do automatically). How would you recommend going about this, and where would that code reside? Would it be part of the EF classes or would every entity I received from the DB need to be passed through some sort of "builder" to construct a decorated object from a Product and its list of Modifications?
I am not entirely sure if I understood your question correctly, but here goes: You can create partial classes to those defined in your EF model. You could define a common interface and use the partial classes to implement that interface.
For example:
public interface IProduct{
public int GetNumThings();
}
public partial class Product : IProduct{
public int GetNumThings()
{
...
}
}
public partial class Modification: IProduct{
public int GetNumThings()
{
...
}
}

DDD: Can a Value Object have lists inside them?

I'm not well versed in domain driven design and I've recently started created a domain model for a project. I still haven't decided on an ORM (though I will likely go with NHibernate) and I am currently trying to ensure that my Value Objects should be just that.
I have a few VOs that have almost no behavior other than to encapsulate "like" terms, for instance:
public class Referral {
public Case Case { get; set; } // this is the a reference to the aggregate root
public ReferralType ReferralType { get; set; } // this is an enum
public string ReferralTypeOther { get; set; }
} // etc, etc.
This particular class has a reference to "Case" which is two levels up, so if say I were going to access a Referral I could go: case.social.referral (Case, Social and Referral are all classes, there is a single Social inside a Case and there is a single Referral inside a Social). Now that I am looking at it as I type it, I don't think I need a Case in the Referral since it will be accessible through the Social entity, correct?
Now, there is no doubt in my mind this is something that should be a VO, and the method I plan to use to persist this to the database is to either have NHibernate assign it a surrogate identifier (which I am still not too clear on, if anyone could please elaborate on that too it would help me out, since I don't know if the surrogate identifier requires that I have an Id in my VO already or if it can operate without one) and/or a protected Id property that would not be exposed outside the Referral class (for the sole purpose of persisting to the DB).
Now on to my title question: Should a VO have a collection, (in my case a List) inside it? I can only think of this as a one-to-many relationship in the database but since there is no identity it didn't seem adequate to make the class an entity. Below is the code:
public class LivingSituation {
private IList<AdultAtHome> AdultsAtHome { get; set; }
public ResidingWith CurrentlyResidingWith { get; set } // this is an enum
} // etc, etc.
This class currently doesn't have an Id and the AdultsAtHome class just has intrinsic types (string, int). So I am not sure if this should be an entity or if it can remain as a VO and I just need to configure my ORM to use a 1:m relationship for this using their own tables and a private/protected Id field so that the ORM can persist to the DB.
Also, should I go with normalized tables for each of my classes, or not? I think I would only need to use a table per class when there is a possibility of having multiple instances of the class assigned to an entity or value object and/or there is the possibility of having collections 1:m relationships with some of those objects. I have no problem with using a single table for certain value objects that have intrinsic types but with nested types I think it would be advantageous to use normalized tables. Any suggestions on this as well?
Sorry for being so verbose with the multiple questions:
1) Do I need a surrogate identifier (with say NHibernate) for my value objects?
2) If #1 is yes, then does this need to be private/protected so that my value object "remains" a value object in concept?
3) Can a value object have other value objects (in say, a List) or would that constitute an entity? (I think the answer to this is no, but I'd prefer to be sure before I proceed further.)
4) Do I need a reference to the aggregate root from a value object that is a few levels down from the aggregate root? (I don't think I do, this is likely an oversight on my part when writing the model, anyone agree?)
5) Is it OK to use normalized tables for certain things (like nested types and/or types with collections as properties which would need their own tables anyway for the 1:m relationship) while having the ORM do the mapping for the simpler value objects to the same table that belongs to my entity?
Thanks again.
Take a look at the answers to related questions here and here
1) Yes - If you're storing VOs in their own table
2) If you can use a private/protected ID property, then great. Alternatively, you might use explicit interfaces to 'hide' the ID property.
But, reading into your question, are you suggesting that developers who see an ID property will automatically assume the object is an entity? If so, they need (re)training.
3) Yes it can, but with the following restrictions:
It should be quite rare
It should only reference other VOs
Also, consider this: VOs shouldn't stick around. Would it be easy/efficient to re-create the entire VO every time it's needed? If not, make it an Entity.
4) Depends on how you want to implement your Aggregate Locking. If you want to use Ayende's solution, the answer is yes. Otherwise, you would need a mechanism to traverse the object graph back to the Aggregate Root.
5) Yes. Don't forget that DDD is Persistence Ignorant (in an ideal world!).
However...
I believe Referral should be an Entity. Imagine these conversations:
Conversation 1:
Tom: "Hey Joe! Can you give me David Jone's referral?"
Joe: "Which one?"
Tom: "Sorry, I mean Referral No.123"
Conversation 2:
Tom: "Hey Joe! Can you give me David Jone's referral?"
Joe: "Which one?"
Tom: "I don't care - just give me any"
Conversation 1 suggests that Referral is an Entity, whereas conversation 2 suggests it's a VO.
One more thing: Does Referral.ReferralType change during it's lifetime (there's another hint that it should be an Entity)? If it doesn't change, consider using polyporphism and let NH handle it.
Hope that helps!

What is the proper object relationship? (C#)

I had a quick question about the proper object relationship I should set up for this situation:
I have a Customer object with associated parameters and a depot object with associated parameters. Each depot serves a set of customers and the customer needs access to particular information for their respective depot.
I'm wondering what the proper relationship I should set up so that a set of customer objects all reference the same instance of a particular depot object. I wanted to be sure it wasn't creating a duplicate Depot object for each customer. Furthermore, i'd like to be able to change properties of the Depot without going through the customer itself.
I know this is probably a fairly basic question but C# has so many different "features" it gets confusing from time to time.
Thanks for your help!
Charlie
If I understand your question correctly, I think a solution to your problem might be an OR mapper. Microsoft provides two OR mappers at the moment, LINQ to SQL and Entity Framework. If you are using .NET 3.5, I recommend using LINQ to SQL, but if you are able to experiment with .NET 4.0, I would highly recommend looking into Entity Framework. (I discourage the use of Entity Framework in .NET 3.5, as it was released very prematurely and has a LOT of problems.)
Both of these OR mappers provide visual modeling tools that allow you to build a conceptual entity model. With LINQ to SQL, you can generate a model from your database, which will provide you with entity classes, as well as associations between those classes (representing your foreign keys from your DB schema). The LINQ to SQL framework will handle generating SQL queries for you, and will automatically map database query results into object graphs. Relationships such as the one you described, with multiple customers in a set referencing the same single department are handled automatically for you, you don't need to worry about them at all. You also have the ability to query your database using LINQ, and can avoid having to write a significant amount of stored procedures and plumbing/mapping code.
If you use .NET 4.0, Entity Framework is literally LINQ to SQL on steroids. It supports everything LINQ to SQL does, and a hell of a lot more. It supports model-driven design, allowing you to build a conceptual model from which code AND database schema are generated. It supports a much wider variety of mappings, providing a much more flexible platform. It also provides Entity SQL (eSQL), which is a text-based query language that can be used to query the model in addition to LINQ to Entities. Line LINQ to SQL, it will solve the scenario you used as an example, as well as many others.
OR mappers can be a huge time, money, and effort saver, greatly reducing the amount of effort required to interact with a relational database. They provide both dynamic querying as well as dynamic, optimistic updates/inserts/deletes with conflict resolution.
This sounds like you've got a Many-to-many relationship going on. (Customers know about their Depots, and vice versa)
Ideally this seems best suited for a database application where you define a weak-entity table ... Of course using a database is overkill if we're talking about 10 Customers and 10 Depots...
Assuming a database is overkill, this can be modeled in code with some Dictionarys. Assuming you're using int for the unique identifiers for both Depot and Customer you could create something like the following:
// creating a derived class for readability.
public class DepotIDToListOfCustomerIDs : Dictionary<int,List<int>> {}
public class CustomerIDToListOfDepotIDs : Dictionary<int,List<int>> {}
public class DepotIDToDepotObject : Dictionary<int,Depot>{}
public class CustomerIDToCustomerObject : Dictionary<int, Customer>{}
//...
// class scope for a class that manages all these objects...
DepotIDToListOfCustomerIDs _d2cl = new DepotIDToListOfCustomerIDs();
CustomerIDToListOfDepotIDs _c2dl = new CustomerIDToListOfDepotIDs();
DepotIDToDepotObject _d2do = new DepotIDToDepotObject();
CustomerIDToCustomerObject _c2co = new CustomerIDToCustomerObject();
//...
// Populate all the lists with the cross referenced info.
//...
// in a method that needs to build a list of depots for a given customer
// param: Customer c
if (_c2dl.ContainsKey(c.ID))
{
List<int> dids=_c2dl[c.ID];
List<Depot> ds=new List<Depot>();
foreach(int did in dids)
{
if (_d2do.ContainsKey(did))
ds.Add(_d2do[did]);
}
}
// building the list of customers for a Depot would be similar to the above code.
EDIT 1: note that with the code above, I've crafted it to avoid circular references. Having a customer reference a depot that also references that same customer will prevent these from being quickly garbage collected. If these objects will persist for the entirety of the applications lifespan a simpler approach certainly could be taken. In that approach you'd have two lists, one of Customer instances, the other would be a list of Depot instances. The Customer and Depot would contain lists of Depots and Customers respectively. However, you will still need two dictionaries in order to resolve the Depot IDs for the customers, and vice versa. The resulting code would be 99% the same as the above.
EDIT 2:
As is outlined in others replies you can (and should) have an object broker model that makes the relationships and answers questions about the relationships. For those who have misread my code; it is by no means intended to craft the absolute and full object model for this situation. However, it is intended to illustrate how the object broker would manage these relationships in a manner that prevents circular references. You have my apologies for the confusion it caused on the first go around. And my thanks for illustrating a good OO presentation that would be readily consumed by others.
In reply to #Jason D, and for the sake of #Nitax: I'm really skimming the surface, because while it's basically easy, it also can get complicated. There's no way I'm going to re-write it better than Martin Fowler either (certainly not in 10 minutes).
You first have to sort out the issue of only 1 object in memory that refers to a specific depot. We'll achieve that with something called a Repository. CustomerRepository has a GetCustomer() method, and the DepotRepository has a GetDepot() method. I'm going to wave my hands and pretend that just happens.
Second you need to need to write some tests that indicate how you want the code to work. I can't know that, but bear with me anyways.
// sample code for how we access customers and depots
Customer customer = Repositories.CustomerRepository.GetCustomer("Bob");
Depot depot = Repositories.DepotRepository.GetDepot("Texas SW 17");
Now the hard part here is: How do you want to model the relationship? In OO systems you don't really have to do anything. In C# I could just do the following.
Customers keep a list of the depots they are with
class Customer
{
public IList<Depot> Depots { get { return _depotList; } }
}
alternatively, Depots keep a list of the customers they are with
class Depot
{
public IList<Customer> Customers { get { return _customerList; } }
}
// * code is very brief to illustrate.
In it's most basic form, any number of Customers can refer to any number of Depots. m:n solved. References are cheap in OO.
Mind you, the problem we hit is that while the Customer can keep a list of references to all the depot's it cares about (first example), there's not an easy way for the Depot to enumerate all the Customers.
To get a list of all Customers for a Depot (first example) we have to write code that iterates over all customers and checks the customer.Depots property:
List<Customer> CustomersForDepot(Depot depot)
{
List<Customer> allCustomers = Repositories.CustomerRepository.AllCustomers();
List<Customer> customersForDepot = new List<Customer>();
foreach( Customer customer in allCustomers )
{
if( customer.Depots.Contains(depot) )
{
customersForDepot.Add(customer);
}
}
return customersForDepot;
}
If we were using Linq, we could write it as
var depotQuery = from o in allCustomers
where o.Depots.Contains(depot)
select o;
return query.ToList();
Have 10,000,000 Customers stored in a database? Ouch! You really don't want to have to load all 10,000,000 customers each time a Depot needs to determine its' customers. On the other hand, if you only have 10 Depots, a query loading all Depots once and a while isn't a big deal. You should always think about your data and your data access strategy.
We could have the list in both Customer and Depot. When we do that we have to be careful about the implementation. When adding or removing an association, we need to make the change to both lists at once. Otherwise we have customers thinking they are associated with a depot, but the depot doesn't know anything about the customer.
If we don't like that, and decide we don't really need to couple the objects so tightly. We can remove the explicit List's and introduce a third object that is just the relationship (and also include another repository).
class CustomerDepotAssociation
{
public Customer { get; }
public Depot { get; }
}
class CustomerDepotAssociationRepository
{
IList<Customer> GetCustomersFor(Depot depot) ...
IList<Depot> GetDepotsFor(Customer customer) ...
void Associate(Depot depot, Customer customer) ...
void DeAssociate(Depot depot, Customer customer) ...
}
It's yet another alternative. The repository for the association doesn't need to expose how it associates Customers to Depots (and by the way, from what I can tell, this is what #Jason D's code is attempting to do)
I might prefer the separate object in this instance because what we're saying is the association of Customer and Depot is an entity unto itself.
So go ahead and read some Domain Driven Design books, and also buy Martin Fowlers PoEAA (Patterns of Enterprise Application Architecture)
Hope this is self-explanatory.
OO:
ER:

Categories