For example I have following domain model:
class Order {
public virtual int Id {get; protected set;}
public virtual BaseStatus Status {get; set;}
}
abstract class BaseStatus {
public virtual int Id {get; protected set;}
public abstract string Name {get;}
}
class Approved : BaseStatus {
public override string Name
{
get { return "Approved"; }
}
}
So now what I wan't to have is two tables, Orders and Statuses. Where Orders table will have StatusId column.
The question is about API of changing order status. If I do the following:
order.Status = new Approved();
That will lead to creation of new row in statuses table.
Currently I have created following helper:
class StatusesFactory {
ISession session;
public StatusesFactory(ISession session){
this.session = session;
}
public GetStatus<T> where T : BaseStatus, new() {
T status = session.QueryOver<T>.SingleOrDefault();
if(status == null){
status = new T();
session.SaveOrUpdate(status);
}
return status;
}
}
And when I want to set status I'm using such code:
order.Status = statusesFactory.GetStatus<Approved>();
It seems to work fine, but to be complex with no reason. I'm using NHibernate but I think the same question may be applied to any ORM. The reason for such a thing is easy deployment on empty data base so that it is filled on first requests.
How do you handle dictionary tables?
Does my approach have obvious down sides that I can't see?
One problem that I see here is when I need to get all possible statuses I cant use code like:
session.QueryOver().List();
because not all statuses may be created yet.
So what do you think?
good question ...
i'd think that your Approved-class should use make use of the singleton pattern, since there can be only one Approved-state ...
the list of all existing vs. all possible states is a bit more difficult ... the possible states depend on what classes inherit from BaseState... i have no idea how to find those fast, since they don't have to reside in the current assembly, or even in a loaded assembly ... you should think about a static list of all subclasses singleton objects in BaseStatus ...
Related
I pretty want to understand how to organize my code. Let's say i have this class called "Brand" which has a "Product" object:
public class Brand {
public int ID { get; set; }
public int name { get; set; }
public Product product { get; set; }
public void add(Brand brand)
{
// Database logic
}
}
And this class called product
public class Product {
public int ID { get; set; }
public int name { get; set; }
}
What i want to know is should i have a method AddProduct inside product class or should the method be on the top class "Brand". That is my confusion.
In order to make better sense of this, think about separation of concerns and single responsiblity. The answer in this post is a nice way of putting this.
Right now you have an object called Brand that contains a method Add and some properties related to being a Brand object. This means that not only is the Brand charged with managing itself, it's also charged with managing it's own interaction with the database. You are fixing to have a similar coupling between the Product and the database as well. Then what happens when you have a collection of brands, and you realize each brand should have a collection of products, and they all have Database logic strewn throughout? Then, say you notice that each Product needs a list of ingredients, so you have to add that, so the ingredients need database logic, etc. etc. You can see this gets very confusing very quickly.
So really, you should have a third class that is responsible for managing database objects, and that class will have methods to call that take your Brand and Product objects as parameters and interact with the database internally. Now you have abstracted your database logic away from your Brand and Product logic, so the Database class can do what it's built for and no more, and the Brand and Class objects can exist as defined wrappers for related data and no more. Everything is now divided so each class represents a single simple concept. Brand class exists to represent brand data. Database class exists to interact with the database.
I'm sure you get the concept and you may have seen this a thousand times already, but thinking like this will help you spot what needs to change and find much simpler, cleaner, more maintainable solutions.
The way you declared the product is using the C# Auto Property.
First of all, you should ask yourself do you need the product to be visible as public member, or you want to encapsulate the logic of setting the product.
If the answer is that you want to want the Product to be able to set outside, then there is no need to declare any additional method:
public class Brand
{
public int Id { get; set; }
public string Name { get; set; }
public IProduct Product { get; set; }
}
public static void Main(string[] args)
{
var brand = new Brand
{
Id = 1,
Name = "Name",
Product = new Product()
};
}
However, if you want to encapsulate the way you set the product then consider using either Composition or Aggregation approaches:
public class Brand
{
private int _id;
public string _name;
private readonly IProduct _product;
public Brand(IProduct product, int id, string name )
{
_product = product;
_id = id;
_name = name;
}
}
public static void Main(string[] args)
{
var brand = new Brand(new Product(), 1, "prd");
}
Note: if you still want to be able to set the product after object declaration, consider a different name for the method, like SetProduct or something with close meaning, because AddProduct means that you are dealing with the collection of Products.
I have 3 classes
public class ActivityLog
{
// The activity log affects an employee
public int EmployeeID { get; set; }
public Employee Employee { get; set; }
// The activity log affects a department
public int DepartmentID { get; set; }
public Department Department { get; set; }
}
In this example there are two different object types that could be displayed on the view, but in reality there are much more types that differ and for which it doesn't seem sensible to move it to its own inheritance model.
I would like to be able to do the below:
public class ActivityLog<T>
{
// The activity log affects an unknown type
public T ConcernedObjectID { get; set; }
public T ConcernedObject { get; set; }
}
Right now we have a lot of null checks in our view (if employee is null then use department).
Is this something that entity framework can help with somehow, or would it be best to implement a code only solution (e.g. Interfaces)?
I think you have a design problem here. The ActivityLog class tries to do too much. Its both an entry in the log for an employee and for a department. Which are completely different things. The only thing they have in common is that they can be put into an activity log.
I would either use a common interface or an abstract base class. You can then use the asp.net equivalent of data templates to visualize the data.
So something like this:
public abstract class ActivityLogEntry
{
int Id { get; }
}
public EmployeeActivityLogEntry : ActivityLogEntry
{
Employee Employee {get;}
}
public DepartmentActivityLogEntry : ActivityLogEntry
{
Department Department {get;}
}
Another thing that can help you with null checks is to make it explicit that something can be null. I use the Optional NuGet package for that. This gives you something like this
Option<Employee> Employee {get; }
public string ToString()
{
return this.Employee.Match(e => e.Name, () => "");
}
In this case you cannot directly access the Employee that is captured in the Option. Instead you have to provide a Func for what to do when there is an Employee (its not null) and for when there isn't. There are a lot more helper functions in the optional library. It makes it a lot clearer that you need to handle both cases. You can no longer be surprised by something begin null.
(Of course you should not use Option<T> for everything. Only use it on properties that can sometimes be null. Not on properties that should never be null, or you start hiding bugs from yourself).
I have a design like this:
public class Employee {
//...
}
public class Company {
private IList<Employee> _employees;
public IList<Employee> Employees {
get { return _employees; }
set {
if (_employees == value) {
return;
}
_employees = value;
//Some logic here. Eg:
//Raise PropertyChanged
//Iterate over the new values to suscribe to some events, etc.
}
}
}
when I try to do something like:
var employees = session.Query<Company>().Fetch(x => x.Employees).ToList();
it throws a LazyInitializationException:
illegal access to loading collection
The only workaround I've found is moving the logic to a method, making this method public (and virtual) and calling the method for every instance in employees, but I don't like that since I will be calling that method from my repositories.
Any ideas?
You are mixing fetching data from the database with control logic. I'd recommend fetching the data into simple value objects. Then transform it into your Company and Employee logic-laden classes afterwards. That way you separate data entities from functionality based on that data.
In Nhibernate you collection class should not be exposed to the out side world. Your typical domain would look like this
public class Company
{
public virtual String Id { get; set; }
public virtual ICollection<Employee> Employees { get; protected set; }
public Company()
{
Employees = new List<Employee>();
}
public void AddEmployee(Employee employee)
{
if (Employees.Contains(employee))
return;
Employees.Add(employee);
employee.Company = this;
}
public void RemoveEmployee(Employee employee)
{
if (!Employees.Contains(employee))
return;
Employees.Remove(employee);
}
}
public class Employee
{
public virtual String Id { get; set; }
public virtual String FullName { get; set; }
public virtual Company Company { get; set; }
}
I agree with the first responder who said to user view models and INPC those, but if you want to bind directly to your domain objects, you can inject INPC directly into your domain objects.
Please see this original post from Ayende and this updated one from Ricardo
I guess you are using 'property' as collection accessor in your mapping, if so the behavior you describe is the expected one when your code tries to modify the collection.
If you want to use that pattern in your domain model, you should change collection accessor to 'field' (with the appropriate naming strategy), in order to tell NHibernate to set the backing field '_employees' and not the property 'Employees'.
This will not trigger your code that tries to access the collection anymore.
I have an Entity Framework Model created using Entity Framework Code First that is using Table Per Hierarchy inheritance where the structure looks a little like this:
public abstract class BaseState
{
public int Id { get; set; }
public string StateName { get; set; }
// etcetera
}
public class CreatedState : BaseState
{
public User Owner { get; set; }
}
public class UpdatedState : BaseState
{
public User Owner { get; set; }
}
Now what that creates is in my BaseStates table I have Owner_Id and Owner_Id1 stored. But given that no class will ever be both a CreatedState and an UpdatedState it seems as though it would be logical to use a single Owner_Id for both. Which would also make it easier to follow the database.
My basic question is: Is this possible with Code First EF4?
I have tried to map the columns:
public class CreatedState : BaseState
{
[Column("OwnerId")]
public User Owner { get; set; }
}
public class UpdatedState : BaseState
{
[Column("OwnerId")]
public User Owner { get; set; }
}
That appeared to have no effect.
Then I tried creating a shared parent class, which is probably more correct OO anyway:
public abstract class OwnedState : BaseState
{
public User Owner { get; set; }
}
public class CreatedState : OwnedState
{
}
public class UpdatedState : OwnedState
{
}
Again, no dice. Or, more worryingly, this appears to work in some cases and not in others ( obviously my real configuration is slightly more complex ) when I can see precisely no difference between the classes where it does work.
Edit for more detail on what fails:
I have two fields that behave in the way I have described above, we might call the associated classes OwnedState and ActivityState, both of which I have created as an abstract class in the way shown in my last example. OwnedState has two classes that derive from it, ActivityState has three. In the database I have ActivityState_Id but also OwnedState_Id and OwnedState_Id1.
I can see no difference at all between the OwnedState and ActivityState classes aside from the type that they reference ( both other entities ) and yet in the database it appears as though EF has somehow interpreted them differently- I don't understand the EF internals well enough to know how it makes that decision.
If you want to have one Owner_ID to have both CreatedState and UpdatedState to refer to, then the User Owner should be placed in the BaseState.
I don't know what you are trying to do with this, but logically, you wouldn't be having CreatedState and UpdatedState as classes, but more of values of State property (or column in database) to save the state (Created or Updated). But, again, maybe you are trying something else with this.. I guess.
In my domain model I have an Entity object that looks as follows:
public class Group
{
public int idGroup { get; set; }
public string Description { get; set; }
}
I have a repository for this object:
public class GroupRepository : IGroupRepository
{
public Group LoadGroup(int idGroup)
{
//imitation of SQL data reader
Group g = new Group();
g.idGroup = Convert.ToInt32(r["idTipoGrupo"]);
g.Description = Convert.ToString(r["Descricao"]);
return g;
}
}
But now I need to get some extra information from data store about Group objects through a new function in my created repository, here are the fields I need:
public bool HasChildGroups { get; set; }
public int ChildGroupsCount { get; set; }
public bool HasDeals { get; set; }
public int DealsCount { get; set; }
These properties look to me like a "service" or "helper" properties and I don't plan to use them everywhere in my application, only few times, but I need them. The simplest thing I could think of is that I added these "service" properties to my Group object and created a method in my repository that populates them. But I consider doing this wrong, as it is the Entity and I don't need them in here. So where should I keep such "service" objects? Do I have to create a new class that inherits from Group like this:
public class GroupHelper : Group
{
public bool HasChildGroups { get; set; }
public int ChildGroupsCount { get; set; }
public bool HasDeals { get; set; }
public int DealsCount { get; set; }
}
Or should I consider using some Data Transfer Objects?
How would you solve this problem?
Any help appreciated.
The first question to ask is how the state of the proposed GroupHelper object is managed. Attributes such as HasChildGroups seems like they would be altered as a result of behaviors invoked on a Group entity. If so, then they should be first class entities in your domain model, perhaps event part of the group entity itself. If the properties are managed outside of your domain model then you can just query that data as you would any other external data source. I would have this be a standalone object, perhaps called something like GroupInfo not extending Group itself.
What seems to be the issue here is that you have query requirements that aren't in alignment with the shape of your entities. In that case you have the flexibility to decouple your read-models from your domain models. Read-models are intended to fulfill query requirements and your domain models are intended to host behavior associated with your domain.
HasChildGroups [...] look to me like a "service" or "helper" properties [...] But I consider doing this wrong, as it is the Entity and I don't need them in here.
If you concider your Group object to be a data access object and you have a separate model for, say, viewdata, you're right.
But this may also be a fat class, providing in view-specific and database-specific code. It's not plain wrong.
You could indeed create a GroupDTO class that provides the properties you require in the application but not for the data access, to separate concerns.