Nestjs: Cast complex Entity to Dto - mapping

I'm trying to cast a complex Entity to a Dto. I would like to remove some values which are in the entity from the DTO.
My entity looks like this (For simplicity a large part of the entity is omitted):
export class ResultEntity {
constructor(
public id: string,
public userId: string,
public results: CalculationOutputEntity[] = [],
public item: Item = new Item(),
) { }
}
export class Item {
constructor(
public privat: Private = new Private(),
public state: State = new State(),
public combined: number = 0,
) { }
}
export class State {
constructor(
public numberA: number = 0,
public numberB: number = 0,
public numberC: number = 0,
public numberD: number = 0,
) { }
}
I have found a solution which works very well for simple entities: Cast entity to dto
If I adopt this suggestion of the custom interceptor, removing the id or the whole item property works.
I have tried two possibilities tot define my DTOs:
It returns only the id and the item as a whole.
#Exclude()
export class AdvisoryResultDto {
#Expose()
public id: string;
public userId: string;
public results: CalculationOutputDto[];
#Expose()
public item: Item;
}
This solution returns everything except the item property.
export class AdvisoryResultDto {
public id: string;
public userId: string;
public results: CalculationOutputDto[];
#Exclude()
public item: Item;
}
The problem now is that I want to remove only certain values within the item property. So for example the private field and within the state-property numberB.
I would like to have the possibility within the nested classes to remove single values also with Exclude().
So for example:
export class AdvisoryResultDto {
public id: string;
public userId: string;
public results: CalculationOutputDto[];
public item: Item;
}
export class Item {
#Exclude()
public privat: PrivateDto;
public state: StateDto;
public combined: number;
}
export class StateDto {
public numberA: number;
#Exclude()
public numberB: number;
public numberC: number;
public numberD: number;
}
Unfortunately I can't find anything about this exact problem. To take over the mapping manually would also not be a solution, since the CalculationOutput is by far more complex and is nested with many classes and properties.
Am I just missing a small step or is it not possible with Expose and Exclude from the class-transformer? If not I would appreciate another solution.

So i found the soulution in the documentation of the class-transformer package: https://github.com/typestack/class-transformer#working-with-nested-objects
I need to add the #Type-Decorator to nested classes
The solution:
#Expose()
export class AdvisoryResultDto {
public id: string;
public userId: string;
public results: CalculationOutputDto[];
#Type(() => Item)
public item: Item;
}
export class Item {
#Exclude()
#Type(() => PrivateDto)
public privat: PrivateDto;
#Expose()
#Type(() => StateDto)
public state: StateDto;
public combined: number;
}
export class StateDto {
public numberA: number;
#Exclude()
public numberB: number;
public numberC: number;
public numberD: number;
}

Why not make a constructor and then initalize DTO with only the required values from the entity? Just pass the entity object to DTO's constructor and remove the fields from DTO.

Related

Model and data annotation in C# and Vue.js

Suppose I have a business object: (C#)
public class ModelA {
public int id {get;set;}
[Required, MyCustomAttribute(...)]
public string str {get;set;}
}
Then I have a ModelAController: (C#)
[Route("api/[controller]")]
[ApiController]
public class ModelAController : Controller
{
// ... some contructors and readonly database ...
[HttpPut("read")]
public ActionResult<ModelA> Read() {
return db.Read<ModelA>();
}
}
Then I have some Vue component: (vue.js)
import ...
export default {
data () {
return {
annotations: '',
model: '',
};
},
created: function()
{
this.values = Read('ModelA'); // reads data in json format returned by ModelAController.Read()
this.annotation = // ?????
},
};
My question is; From a Vue component, how do I access the annotations "Required" and "MyCustomAttribute" and others. Should I add a method in my controller to get these Attribute?
[HttpPut("attributes")]
public ActionResult<Attribute[]> Attributes(string propertyName) {
return getAttributesOf(propertyName);
// getAttributesOf("str") would return Attribute[]{ RequiredAttribute, MyCustomAttribute(...)}
}
Is there a better way?

TypeORM - Getter & Setter problem with joinColumns - Cannot read property 'joinColumns' of undefined

I created 2 entities User and Photo with relations. When I try to find all data of User with it's relations, I get this error:
TypeError: Cannot read property 'joinColumns' of undefined
It works fine as soon as I remove my Getter & Setter and set the properties to public access and removing the underscore. But I want to keep Getters & Setters actually.
user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { Photo } from './photo.entity';
#Entity()
export class User {
#PrimaryGeneratedColumn({ name: 'id' })
private _id: number;
#Column({ name: 'name' })
private _name: string;
#OneToMany(type => Photo, photo => photo.user)
private _photos: Photo[];
public get id(): number {
return this._id;
}
public set id(value: number) {
this._id = value;
}
public get name(): string {
return this._name;
}
public set name(value: string) {
this._name = value;
}
public get photos(): Photo[] {
return this._photos;
}
public set photos(value: Photo[]) {
this._photos = value;
}
}
photo.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
import { User } from './user.entity';
#Entity()
export class Photo {
#PrimaryGeneratedColumn({ name: 'id' })
private _id: number;
#Column({ name: 'url' })
private _url: string;
#ManyToOne(type => User, user => user.photos)
private _user: User;
public get id(): number {
return this._id;
}
public set id(value: number) {
this._id = value;
}
public get url(): string {
return this._url;
}
public set url(value: string) {
this._url = value;
}
public get user(): User {
return this._user;
}
public set user(value: User) {
this._user = value;
}
}
user.repository.ts
public async findUsers(): Promise<User[]> {
return await this.find({ relations: ['_photos'] }); // photos (without _) isn't working as well
}

Orika: mapping fields of 2 classes to one class

Is there a way to map fields from classes to one using Orika.
Can't find the solution in the orika documentation.
In the example the fields test & name from class ObjectOne should be mapped to the corresponding fields ObjectNew.
public class ObjectOne {
private String test;
private String name;
private String id;
public ObjectOne(String id,String test, String name){
this.id=id;
this.test=test;
this.name=name;
}
}
The same with field sheet from ObjectTwo
public class ObjectTwo {
private String sheet;
private String id;
public ObjectTwo(String id,String sheet){
this.id=id;
this.sheet=sheet;
}
}
Code for ObjectNew
public class ObjectNew {
private String id;
private String test;
private String name;
private String sheet;
public ObjectNew(String id,String test,String name,String sheet){
this.id=id;
this.test=test;
this.name = name;
this.sheet = sheet;
}
}
Fields from both classes ObjectOne & ObjectTwo should initiate new object ObjectNew when id's of classes ObjectOne and ObjectTwo are the same.
Any ideas how to handle this?
Kind Regards
I would suggest to wrap the source objects into one source wrapper object and map this new wrapper object with your new object:
public class objectWrapper{
private objectOne objectOne;
private objectTwo objectTwo;
}

using stored procedure in entity framework

I am using asp.net mvc 5 and C# with Entity Framework... I have model and domain classes for function... now I need to use stored procedure.... which I am struggling at the movement.
I am following code first existing database and I have stored procedure written there. My question is how I can call that stored procedure in my web application.
Stored procedure:
ALTER PROCEDURE [dbo].[GetFunctionByID](
#FunctionId INT
)
AS
BEGIN
SELECT *
FROM Functions As Fun
WHERE Function_ID = #FunctionId
END
Domain class:
public class Functions
{
public Functions()
{
}
public int Function_ID { get; set; }
public string Title { get; set; }
public int Hierarchy_level { get; set; }
}
Function model:
[Table("Functions")]
public class App_Functions
{
public App_Functions()
{
}
[Key]
public int Function_ID { get; set; }
[StringLength(50)]
[Required]
public string Title { get; set; }
public int Hierarchy_level { get; set; }
//public virtual ICollection<App_Controllers> App_Controllers { get; set; }*/
}
BaseContext:
public class BaseContext<TContext> : DbContext where TContext : DbContext
{
static BaseContext()
{
Database.SetInitializer<TContext>(null);
}
protected BaseContext()
: base("name = ApplicationDbConnection")
{ }
}
Function context:
public class FunctionsContext : BaseContext<FunctionsContext>
{
public DbSet<App_Functions> Functions { get; set; }
}
You need to create a model class that contains all stored procedure properties like below.
Also because Entity Framework model class needs primary key, you can create a fake key by using Guid.
public class GetFunctionByID
{
[Key]
public Guid? GetFunctionByID { get; set; }
// All the other properties.
}
then register the GetFunctionByID model class in your DbContext.
public class FunctionsContext : BaseContext<FunctionsContext>
{
public DbSet<App_Functions> Functions { get; set; }
public DbSet<GetFunctionByID> GetFunctionByIds {get;set;}
}
When you call your stored procedure, just see below:
var functionId = yourIdParameter;
var result = db.Database.SqlQuery<GetFunctionByID>("GetFunctionByID #FunctionId", new SqlParameter("#FunctionId", functionId)).ToList());
After importing stored procedure, you can create object of stored procedure pass the parameter like function
using (var entity = new FunctionsContext())
{
var DBdata = entity.GetFunctionByID(5).ToList<Functions>();
}
or you can also use SqlQuery
using (var entity = new FunctionsContext())
{
var Parameter = new SqlParameter {
ParameterName = "FunctionId",
Value = 5
};
var DBdata = entity.Database.SqlQuery<Course>("exec GetFunctionByID #FunctionId ", Parameter).ToList<Functions>();
}
You can call a stored procedure using SqlQuery (See here)
// Prepare the query
var query = context.Functions.SqlQuery(
"EXEC [dbo].[GetFunctionByID] #p1",
new SqlParameter("p1", 200));
// add NoTracking() if required
// Fetch the results
var result = query.ToList();
// Add some tenants to context so we have something for the procedure to return!
AddTenentsToContext(Context);
// ACT
// Get the results by calling the stored procedure from the context extention method
var results = Context.ExecuteStoredProcedure(procedure);
// ASSERT
Assert.AreEqual(expectedCount, results.Count);
}
Mindless passenger has a project that allows you to call a stored proc from entity frame work like this....
using (testentities te = new testentities())
{
//-------------------------------------------------------------
// Simple stored proc
//-------------------------------------------------------------
var parms1 = new testone() { inparm = "abcd" };
var results1 = te.CallStoredProc<testone>(te.testoneproc, parms1);
var r1 = results1.ToList<TestOneResultSet>();
}
... and I am working on a stored procedure framework (here) which you can call like in one of my test methods shown below...
[TestClass]
public class TenantDataBasedTests : BaseIntegrationTest
{
[TestMethod]
public void GetTenantForName_ReturnsOneRecord()
{
// ARRANGE
const int expectedCount = 1;
const string expectedName = "Me";
// Build the paraemeters object
var parameters = new GetTenantForTenantNameParameters
{
TenantName = expectedName
};
// get an instance of the stored procedure passing the parameters
var procedure = new GetTenantForTenantNameProcedure(parameters);
// Initialise the procedure name and schema from procedure attributes
procedure.InitializeFromAttributes();
// Add some tenants to context so we have something for the procedure to return!
AddTenentsToContext(Context);
// ACT
// Get the results by calling the stored procedure from the context extention method
var results = Context.ExecuteStoredProcedure(procedure);
// ASSERT
Assert.AreEqual(expectedCount, results.Count);
}
}
internal class GetTenantForTenantNameParameters
{
[Name("TenantName")]
[Size(100)]
[ParameterDbType(SqlDbType.VarChar)]
public string TenantName { get; set; }
}
[Schema("app")]
[Name("Tenant_GetForTenantName")]
internal class GetTenantForTenantNameProcedure
: StoredProcedureBase<TenantResultRow, GetTenantForTenantNameParameters>
{
public GetTenantForTenantNameProcedure(
GetTenantForTenantNameParameters parameters)
: base(parameters)
{
}
}
If either of those two approaches are any good?
Simple. Just instantiate your entity, set it to an object and pass it to your view in your controller.
Entity
VehicleInfoEntities db = new VehicleInfoEntities();
Stored Procedure
dbo.prcGetMakes()
or
you can add any parameters in your stored procedure inside the brackets ()
dbo.prcGetMakes("BMW")
Controller
public class HomeController : Controller
{
VehicleInfoEntities db = new VehicleInfoEntities();
public ActionResult Index()
{
var makes = db.prcGetMakes(null);
return View(makes);
}
}

How to configure ObjectFactory to call parameterized constructor structuremap

PLEASE: If my question isn't clear, please tell me and I'll try to rephrase it
I need [Default Constructor] in LogOnModel, so it can't be removed.
LoadModel+ModelFactory and LogOnModel are physically in different files in different projects AND project2 has reference to project1 and NOT vice versa.
1 - Let say that
type=typeof(LogOnModel). When ObjectFactory.GetInstance(t) is called I want it to call the
parameterized constructor of LogOnModel and pass it the #params
2 - If I'll add to the parameterized constructor of LogOnModel another parameter,for example
public LogOnModel(string param, IPageService pageService)
so ObjectFacytory should call this constructor without any problems
How to configure/initiate ObjectFactory, so this will work?
Thank you
EDITED
//Project1/file1.cs
public void LoadModel(Type type, string param)
{
var factory = new ModelFactory();
var model = factory.Get(type, **param**);
}
public class ModelFactory : IModelFactory
{
public PageModel Get(Type t, **string param**)
{
//NOW I NEED SOMEHOW TO PASS **param** TO EVERY INSTANCE THAT INHERITS FROM **PageModel**
return ObjectFactory.GetInstance(t) as PageModel;
}
}
//Project2/file2.cs
public class LogOnModel : PageModel
{
public LogOnModel()
{
}
public LogOnModel(string param)
{
}
}
public class Model2 : PageModel
{
public LogOnModel()
{
}
public LogOnModel(string param)
{
}
}
public class Model3 : PageModel
{
public LogOnModel()
{
}
public LogOnModel(string param)
{
}
}
StructureMap will use the constructor with the most parameters by default, so that part is easy. Then you just need to configure the value of param like so:
ObjectFactory.Initialize(i => {
i.For<LogOnModel>().Use<LogOnModel>();
});
When you call the container, use the with method to pass in your parameter:
return ObjectFactory.With("param").EqualTo(param).GetInstance(t) as PageModel;

Resources