Build nested or hierarchical object graphs in C# - object-graph

I have an object hierarchy that can be represented simplistically like:
public class ChannelEntity
{
... public properties ....
public FramesetEntity Frameset { get; set; }
}
public class FramesetEntity
{
... public properties ....
public List<FrameEntity> Frames { get; set; }
}
public class FrameEntity
{
... public properties ....
public List<TimeslotEntity> TimeSlots { get; set; }
}
public class TimeslotEntity
{
... public properties ....
public PlaylistEntity Playlist { get; set; }
}
and so on with some objects containing multiple nested objects. Now I am trying to figure out a generic and elegant way to construct the full object hierarchy with the individual objects available.
A
s a background, I am getting the individual objects from a web service where the return object contains the identifier for the nested child using which I am subsequently again calling the service to get the nested object data. Once I have resolved all the necessary data, I was trying to figure out a way to create the complete object hierarchy using respective builders for the individual objects having the responsibility of creating itself and the necessary childs(through their builders) so that the caller can be isolated from having to create the entire object graph manualy.

Related

Map two classes to the same table

There is a NODES table with dozen of 'small' columns and a LOB column in a legacy DB. A NodeEntity class is mapped to the NODES table.
For performance purposes I do not want to load LOB column every time I access the DB. I know two approaches to achieve this:
Lazy loaded properties
Separate entity class (the idea is taken from here)
Lazy loaded properties are good when you only loading data from DB. But if you have to save entities then there is a risk to lose your data if you forget to fetch lazy loaded properties beforehand.
So I chose the second approach.
I created separate small NodeEntityLite class with properties mapped to non-LOB columns of NODES table. I modified NodeEntity class so it inherits from NodeEntityLite class. I changed the mappings for my classes and used union-subclass for inheritance.
public class NodeEntityLite {
public virtual long Id { get; set; }
public virtual string Code { get; set; }
}
public class NodeEntity : NodeEntityLite {
public virtual string NOTE { get; set; } // type:clob
}
FluentNHibernate mapping for NodeEntityLite class is
public void Override(AutoMapping<NodeEntityLite> mapping) {
mapping.Table("NODES");
mapping.UseUnionSubclassForInheritanceMapping();
}
FluentNHibernate mapping for NodeEntity class is
public void Override(AutoMapping<NodeEntity> mapping) {
mapping.Table("NODES");
mapping.Map(e => e.NOTE).CustomType("StringClob").CustomSqlType("NCLOB");
}
I expected that when I execute select n from NodeEntityLite n where n.Id = :p0 HQL then NHibernate generates SQL commands without NOTE column:
select nodeentity0_.ID as id1_87_,
nodeentity0_.CODE as code2_87_
from from NODES nodeentity0_
where nodeentity0_.ID=:p0;
But NHibernate generates absolutely different SQL command (NOTE column is not skipped as I expected):
select nodeentity0_.ID as id1_87_,
nodeentity0_.CODE as code2_87_,
nodeentity0_.NOTE as note14_87_,
nodeentity0_.clazz_ as clazz_
from ( select ID, CODE, NOTE, 1 as clazz_ from NODES ) nodeentity0_
where nodeentity0_.ID=:p0;
I tried to change inheritance and to use other mappings but without success.
The question is: Can I map several classes to the same table in NHibernate to get access to different columns?
If yes, please give an example.
The solution (based on the suggestions from David Osborne and mxmissile) is not to use inheritance. I use common interface implementation instead of class inheritance. The working code is below:
public interface INodeLite {
long Id { get; set; }
string Code { get; set; }
}
public class NodeEntityLite : INodeLite {
public virtual long Id { get; set; }
public virtual string Code { get; set; }
}
public class NodeEntity : INodeLite {
public virtual long Id { get; set; }
public virtual string Code { get; set; }
public virtual string NOTE { get; set; } // type:clob
}
...
public void Override(AutoMapping<NodeEntityLite> mapping) {
mapping.Table("NODES");
}
...
public void Override(AutoMapping<NodeEntity> mapping) {
mapping.Table("NODES");
mapping.Map(e => e.NOTE).CustomType("StringClob").CustomSqlType("NCLOB");
}
Regardless of the inheritance, NH can map different types to the same table. I have done it, albeit without inheritance.
You should be able to remove this line from the NodeEntityLite override and achieve it:
mapping.UseUnionSubclassForInheritanceMapping();
If this proves unsuccessful, you might need to tune the automapping further. It's definitely possible though.

Create a Parent with existing children in EntityFramework core

I am building a Web API and have two models: Task and Feature:
public class Feature
{
[Key]
public long FeatureId { get; set; }
public string Analyst_comment { get; set; }
public virtual ICollection<User_Task> Tasks { get; set; }
public Feature()
{
}
}
public class User_Task
{
[Key]
public long TaskId { get; set; }
public string What { get; set; }
[ForeignKey("FeatureId")]
public long? FeatureId { get; set; }
public User_Task()
{
}
}
I create Tasks first and then create a Feature that combines few of them. Task creation is successful, however while creating a Feature with existing Tasks, my controller throws an error saying the task already exists:
My FeatureController has following method:
//Create
[HttpPost]
public IActionResult Create([FromBody] Feature item)
{
if (item == null)
{
return BadRequest();
}
** It basically expects that I am creating a Feature with brand new tasks, so I guess I will need some logic here to tell EF Core that incoming tasks with this feature already exist **
_featureRepository.Add(item);
return CreatedAtRoute("GetFeature", new { id = item.FeatureId }, item);
}
How to tell EF core that incoming Feature has Tasks that already exist and it just needs to update the references instead of creating new ones?
My context:
public class WebAPIDataContext : DbContext
{
public WebAPIDataContext(DbContextOptions<WebAPIDataContext> options)
: base(options)
{
}
public DbSet<User_Task> User_Tasks { get; set; }
public DbSet<Feature> Features { get; set; }
}
And repo:
public void Add(Feature item)
{
_context.Features.Add(item);
_context.SaveChanges();
}
When calling Add on a DBSet with a model that was not loaded from EF, it thinks it is untracked and will always assume it is new.
Instead, you need to load the existing record from the dbcontext and map the properties from the data passed into the API to the existing record. Typically that is a manual map from parameter object to domain. Then if you return an object back, you would map that new domain object to a DTO. You can use services like AutoMapper to map the domain to a DTO. When you're done mapping, you only need to call SaveChanges.
Generally speaking, loading the record and mapping the fields is a good thing for the security of your API. You wouldn't want to assume that the passed in data is pristine and honest. When you give the calling code access to all the properties of the entity, you may not be expecting them to change all the fields, and some of those fields could be sensitive.

nHibernate - Fetch with private collection

Is there a way to use Fetch with collection that is private?
This is what i have for code:
public class Owner
{
private ICollection<Cat> _cats = new List<Cat>();
public virtual int Id { get; set; }
public virtual IEnumerable<Cat> Cats { get { return _cats; } }
public virtual void AddCat(Cat cat) { ... }
}
public class Cat
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Owner Owner { get; set; }
}
Most of the time, I want to lazy load the Cats collection, but sometimes I don't. I want to use Fetch in a Linq query to eager load it. I currently get a "could not resolve property: Cats..." exception. I am assuming I get this because I have a Set("_cats", ...) in my ClassMapping, and its looking for the property Cats to be mapped. Is there a way to get Fetch to work with the private collection of Cats?
NHibernate generates proxies from your objects, when they are loaded from database, so the properties you want to map must be virtual. You should make your private cats collection protected virtual and try again. I only mapped properties with a protected setter and a public getter, but this solution may be suitable with full protected properties, too.
You need to specify nosetter access strategy in property mapping.
Take a look at this answer for details: Domain Model with Nhibernate design issue

ORM with entity classes and domain interfaces/classes

I'm trying to decide how to handle domain-level classes and interfaces with respect to objects populated via ORM (NHibernate in this case). I've mocked up a very simple scenario that helps to illustrate my current situation.
public interface ICar
{
public bool PassesEmisionStandards(string state);
public int Horsepower { get; set; }
public string Model { get; set; }
}
public class CarFromDB
{
public int Horsepower { get; set; }
public string Model { get; set; }
}
public class ModelT : CarFromDB, ICar
{
public bool PassesEmissionStandards(string state)
{
return false;
}
public override string ToString()
{
return Model + " with " + Horsepower + " ponies";
}
}
In this case, CarFromDB is the class that's got the mapping via NHibernate to my database. ICar is the interface that my UI/Controller code is handling. ModelT is one of the classes that have instances passed to the UI.
In my actual domain, the PassesEmissionStandards is a complicated method that differs significantly among the different derived classes, and the CarFromDB class has a dozen simple properties along with references to other classes, both singly and in lists. This information is all used in the PassesEmissionStandards equivalent.
I'm confused about the best way to end up with my derived classes decorated with the interface when I start with a populated base class from the ORM. The ideas I've come up with to try to handle this are:
Decorate CarFromDB with ICar and try to come up with a clean way to implement the extensive PassesEmissionStandards method within it or by calling out to other classes for help
Use AutoMapper or the equivalent + a factory to transform my base class objects into derived class objects
Since the derived class type can be identified from a property in the base class, mapp my derived classes for NHibernate and find some way to hook into NHibernate to instruct it which mapped derived class to use.
I feel like this must be a very common issue, but I searched around SO and other places without finding any solid guidelines. Please note: I'm relatively new to ORM and domain modelling and very new to NHibernate. Any help is appreciated.
I don't think that I understand your problem, why canĀ“t you use:
public interface ICar
{
public bool PassesEmisionStandards(string state);
public int Horsepower { get; set; }
public string Model { get; set; }
}
public abstract class CarBase : ICar
{
public int Horsepower { get; set; }
public string Model { get; set; }
public abstract bool PassesEmisionStandards(string state);
}
Or if CarBase is used for all derived classes too, you might want to use strategy pattern
public interface IEmissionCalculator
{
void Calculate(IEmissionCalculatorContext context);
}
public CarBase : ICar
{
internal void Assign(IEmissionCalculator calculator){}
public bool PassesEmisionStandards(string state)
{
//assign all info needed for calculations
var ctx = new IEmissionCalculatorContext { };
return _calculator.Check(ctx);
}
}
You can use the same DB-class, but assign different emission caluclations depending of the type of car.
If that doesn't work either, I would use automapper.

How to prevent private properties in .NET entities from being exposed as public via services?

I'm creating a WCF service that transfers entity objects created via entity framework. I have a User entity that maps to a User db table. There are certain User fields (Password, DateCreated, etc) that I don't want to expose to the client but, because they are non-nullable in the db, Visual Studio requires mappings. Setting these properties as private seems like a good workaround but these properties are converted to public when consumed by a client.
Is there a way around this, or a better approach to take? I'd rather avoid changing these fields at the db level just to make EF happy.
This sounds like to perfect opportunity to segregate the layers of the application. What you should do is create objects that are specific to the WCF layer that act only as Data Transfer Objects (DTO) to the outside consumers.
So, in your WCF service layer you make will your calls to your data access layer (Entity Framework) which retrieves User objects and you should return to your consumer objects constructed with only what you want to expose.
If you do this, you can explicitly control what you make visible to the outside world and also hide any implementation details about what you are doing from a data storage perspective.
As an extremely crude example, in your Entity Framework layer you might have this object:
namespace ACME.DataAccessLayer.Entities
{
public class User
{
public int Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Hash { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
namespace ACME.DataAccessLayer.Services
{
using ACME.DataAccessLayer.Entities;
public class UserService
{
public User GetUser(int id)
{
using (ACMEDataContext dc = new ACMEDataContext())
{
// psuedo code to return your user with Entity Framework
return dc.Users.FirstOrDefault(user => user.Id == id);
}
}
}
}
Then in your WCF later you might have an entity like:
namespace ACME.Services.DataTransferObjects
{
[DataContract]
public class User
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
}
Then you would expose a service endpoint that would return back the DTO as such:
namespace ACME.Services
{
using ACME.DataAccessLayer.Services;
public class PublicWCFService : IUserService
{
public ACME.Services.DataTransferObjects.User GetUser(int userId)
{
ACME.DataAccessLayer.Entities.User entityFrameowrkUser = new UserService().GetUser(userId);
return new ACME.Services.DataTransferObjects.User
{
Id = entityFrameowrkUser.Id,
FirstName = entityFrameowrkUser.FirstName,
LastName = entityFrameowrkUser.LastName
};
}
}
}
Now what you would do is just return the DTO object which will not have any of the attributes, or methods that you may have in the real entities you use in your system.
With this approach, you can safely break the layers of the application into different layers (DLLs) that can easily be shared and extended.
This is a quick example, so let me know if there's anything further that would make this example more clear.
You could always implement IXmlSerializable on the entity object. Then, you would be able to dictate the structure of what is sent to the client (the client would get a different representation, obviously).
Either that, or if you can, add the DataContract attribute to the type, and the DataMember attribute to only the properties you wish to send over the wire.