How to manage DTO Implementaion for Rest-Api in .NET CORE? Alternatives? - rest

I have a quite big query in my WebApi which filters data from different models to send them in a DTO Object to FrontEnd(Angular).
I think DTO could be the right approach because it isn't neccessary for the frontend to get all parameters from all models.
My problem consists in from mapping the DTO Object back to my WebApi Models.
I tried Automapper from NugetPackages but it didn't work. I also heard that AutoMapper isn't the right choice when projects are getting bigger and bigger.
Below is the Code for my DTO object, query and models:
public class ApplicationSettingsDto
{
public string KeyName { get; set; }
public string Wert { get; set; }
public string DefaultValue { get; set; }
public string Description { get; set; }
}
Models:
public partial class ApplicationSettings
{
public string KeyName { get; set; }
public string Wert { get; set; }
public int Typ { get; set; }
public string DisplayOrder { get; set; }
}
public partial class ApplicationSettingsDefaults
{
public Guid Id { get; set; }
public string KeyName { get; set; }
public string Value { get; set; }
public int ProduktOption { get; set; }
}
public partial class Text
{
public string KeyName { get; set; }
public string Sprache { get; set; }
public string Text1 { get; set; }
public DateTime LetzteAenderung { get; set; }
}
Query:
public IQueryable Description()
{
int produktOption = GetProduktOption();
var query = from appl in _repositoryContext.ApplicationSettings
from text in _repositoryContext.Text
from defaults in _repositoryContext.ApplicationSettingsDefaults
//filter DefaultValues
where appl.KeyName.Equals(defaults.KeyName) &&
(defaults.ProduktOption.Equals(produktOption) || defaults.ProduktOption.Equals(65535))
//Filter TextValues
where EF.Functions.Like(text.KeyName, "%" + appl.KeyName) ||
EF.Functions.Like(text.KeyName, "%" + appl.KeyName + "$Descr")
where EF.Functions.Like(text.Sprache, "de-DE")
select new ApplicationSettingsDto()
{
KeyName = appl.KeyName,
Wert = appl.Wert,
DefaultValue = defaults.Value,
Description = text.Text1
}
into output orderby output.KeyName select output;
return query;
}
So this question is not about an detailed implementation, it's only about recommendations for implementing DTO because mapping can be a pain in the *ss, like in my example.
I'm open to new ideas or patterns I don't know yet to try to manage problems like this.
Thanks in Advance ;)

This question is likely to be closed as you have working code, but my recommendation, after years of having tried AutoMapper, reflection based mappings, and hand-written mappings, that you should just stick with what is simplest and works.
You typically have to write the mapping logic for your DTOs once. The code you would write is legible and straightforward. When you move that to AutoMapper, you now end up having an often unrelated and less legible piece of code for something very, very simple.
In the event that you need the mapping logic in another function, extract it to a separate method. In the event that you need it in a separate class, promote that mapping function to a static method on your DTO.
Most of my mapping code looks like:
// Some controller code
da.GetStudents().Select(Map); // Map is the function below
In the controller, the following method is defined:
public StudentDto Map(Student student)
{
if (student == null) return null;
return new StudentDto
{
FirstName = student.FirstName,
...
};
}
Hope that helps.

Related

How to setup my code as DB First in an ORM

I have looked at using EF, nHibernate and Dapper/Dapper.SimpleCRUD. In none of them can I figure out how to represent my use case in regards to my database (SQL Server 2012) model. I am building an ASP.NET website with a grid in C# 4.0/.NET 4.0 (due to technical limitations) that will have CRUD capabilities, with the initial state of the grid being set by dropdowns.
My two tables are set up as such:
Address_Book
|_[EntryID]
|_[Last_Name]
|_[First_Name]
|_[Title]
|_[Office_Num]
|_[Cell_Num]
|_[Home_Num]
|_[Email_Address]
|_[Special_Info]
|_[hr24_Emails]
|_[hr48_Emails]
|_[RM_Emails]
|_[Prestige_Emails]
|_[GEB_Emails]
|_[LAW_Emails]
Distribution
|_[Brand]
|_[Location_Mnemonic]
|_[Location_Code_Numeric]
|_[EntryID]
|_[Division_Mnemonic]
|_[Region_Mnemonic]
|_[Zone_Mnemonic]
|_[District_Mnemonic]
|_[Key]
With a many-to-one relationship between Distribution and Address_Book where Address_book.EntryID = Distribution.EntryID.
Any help with how to set this up would be appreciated. I am having issues managing the CRUD operations manually, so I thought an ORM would help, but I cannot figure it out. Any help is appreciated.
Thanks in advance!
The whole .net CRUD thing is a big realm with a lot of flavors and ways of doing the work. And while I don't know exactly where you are at with this, the following my help out. In my experience EF can handle relationships quite well, though the whole EF learning process is a bit steep and I've shied away from it. I typically use Dapper with extensions and do stuff pseudo-manually. I haven't used the SimpleCrud extension. Since you inherited the DB, hopefully it's set up well and there's a FK constraint on Distribution, Column EntryID.
In Dapper, you could set up your classes like:
using Dapper.Contrib.Extensions;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
namespace Jacrys
{
[Table("dbo.address_book")]
public partial class AddressBook
{
[Dapper.Contrib.Extensions.Key]
public int EntryID { get; set; }
public string Last_Name { get; set; }
public string First_Name { get; set; }
public string Title { get; set; }
public string Office_Num { get; set; }
public string Cell_Num { get; set; }
public string Home_Num { get; set; }
public string Email_Address { get; set; }
public bool Special_Info { get; set; }
public bool hr24_Emails { get; set; }
public bool hr48_Emails { get; set; }
public bool RM_Emails { get; set; }
public bool Prestige_Emails { get; set; }
public bool GEB_Emails { get; set; }
public bool LAW_Emails { get; set; }
//use this only if you need all of the distributions to be
//part of your main AddressBook class
public IEnumerable<Distribution> Distributions { get; set; }
public static AddressBook GetById(short id)
{
using (IDbConnection cn = new SqlConnection("getConnString"))
{
cn.Open();
return cn.Get<AddressBook>(id);
}
}
public static IEnumerable<AddressBook> GetAll()
{
using (IDbConnection cn = new SqlConnection("getConnString"))
{
cn.Open();
return cn.GetAll<AddressBook>();
}
}
public int Insert()
{
using (IDbConnection cn = new SqlConnection("getConnString"))
{
cn.Open();
return (int)cn.Insert(this);
}
}
public bool Update()
{
using (IDbConnection cn = new SqlConnection("getConnString"))
{
cn.Open();
return cn.Update(this);
}
}
public bool Delete()
{
using (IDbConnection cn = new SqlConnection("getConnString"))
{
cn.Open();
return cn.Delete(this);
}
}
}
[Table("dbo.distribution")]
public partial class Distribution
{
[Dapper.Contrib.Extensions.Key]
public int Key { get; set; }
public int EntryID { get; set; }
public string Brand { get; set; }
public string Location_Mnemonic { get; set; }
public int Location_Code_Numeric { get; set; }
public string Division_Mnemonic { get; set; }
public string Region_Mnemonic { get; set; }
public string Zone_Mnemonic { get; set; }
public string District_Mnemonic { get; set; }
//similar CRUD methods to AddressBook follow here
}
}
Then with a GridView like:
<asp:GridView ID="gvAddresses" runat="server" AutoGenerateColumns="true" DataKeyNames="EntryID">
</asp:GridView>
You can load it up in the code behind with (and adding lambda expression for pre-sorting):
gvAddresses.DataSource = Jacrys.AddressBook.GetAll().OrderBy(c=>c.Last_Name);
Any dropdowns you need can be loaded in similar ways.
Everything depends on your needs. If you have a gridview of Distribution, then you can add in a dropdown for Address when in edit mode (in the row data bound event). When you go to update and save, you'll have to find the control in the row and parse it's selected value before saving the record. There really isn't a nifty one single way to get this done. Though, if you have all of your business classes set up with CRUD methods you can wire it all together more simply.

Map custom DTO to breeze entities

Is it possible to map Flatened object to breeze entities? I have a DTO which is built up from multiple datasets but I am having trouble manipulating the data on the client. I would like the custom DTO to be part of the breeze metedata. below is a sample of the DTO.
Public class TimeKeepingItem
{
public int ClientId{ get; set; }
public string ClientName{ get; set; }
public string ClientSurname { get; set; }
public DateTime Date { get; set; }
public string Time { get; set; }
{
get { return Date.DayOfWeek.ToString(); }
}
}
Public class TimeKeepingContainer
{
public List<TimeKeepingItems> TimekeepingItems {get;set;}
//other properties
}
I would like to convert both the above classes to breeze entities on the client.
PW Kad's comment is correct, you can also take a look at the Edmunds and NoDb samples in the Breeze zip.

.Net MVC 4 REST Cannot send Object

I have build a .Net Mvc 4 application and now I want to extend it with REST.
I am using the Entity Framework and I have the following problem.
My goal is to have a system where categories have a number of products and where products can belong to multiple categories.
As follows:
public class Categorie
{
[Key]
public int Id { get; set; }
[Required]
public string Naam { get; set; }
[Required]
public string Omschrijving { get; set; }
public byte[] Plaatje { get; set; }
private List<Product> producten;
public virtual List<Product> Producten
{
get { return producten; }
set { producten = value; }
}
}
public class Product
{
[Key]
public int Id { get; set; }
[Required]
public string Naam { get; set; }
[Required]
public string Omschrijving { get; set; }
[Required]
public double Prijs { get; set; }
private List<Categorie> categorien = new List<Categorie>();
public virtual List<Categorie> Categorien
{
get { return categorien; }
set { categorien = value; }
}
[Required]
public byte[] Plaatje { get; set; }
}
NOTE: There are virtual properties in there so that my entity framework creates a merging table. Normally it links all the categorie's to the products and vice versa.
And my rest looks like:
// GET api/Rest/5
public Product GetProduct(int id)
{
Product product = db.Producten.Find(id);
Product newProduct = new Product();
if (product == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
else
{
product.Categorien = null;
}
newProduct.Id = product.Id;
newProduct.Naam = product.Naam;
newProduct.Omschrijving = product.Omschrijving;
newProduct.Plaatje = product.Plaatje;
newProduct.Prijs = product.Prijs;
newProduct.Categorien = product.Categorien;
return newProduct;
}
First problem: I cannot send any product aslong as it has a categorie. I have to make it null.
Second problem: I cannot send the original product because of the first problem.
I am assuming your problem is with a circular reference during serialization, since categories reference multiple products and products reference multiple categories. One solution is to use Data Transfer Objects (DTO) instead of returning the straight entities you are using for EF. To make it easy to map your entities to the DTO's I would use AutoMapper. This is essentially what you are doing when you create an instance of newProduct in your REST API method, but AutoMapper takes the hard coding and drudgery out of mapping. Your DTO for a product would look very similar but they would not have the virtual navigation properties or the attributes needed by EF. A DTO for a product would look something like this.
public class Categorie
{
public int Id { get; set; }
public string Naam { get; set; }
public string Omschrijving { get; set; }
public byte[] Plaatje { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Naam { get; set; }
public string Omschrijving { get; set; }
public double Prijs { get; set; }
public List<Categorie> categorien = new List<Categorie>();
public List<Categorie> Categorien
{
get { return categorien; }
set { categorien = value; }
}
public byte[] Plaatje { get; set; }
}
Notice that the DTO for Categorie does not contain a list of products, since in this case you want a listing of products. If you keep the field names the same for your DTO's as your entities AutoMapper will handle the mapping automatically. I usually keep the same class name for the DTO's and just distinguish them from the entities by having a different namespace. Your REST API method would look something like this.
// GET api/Rest/5
public Product GetProduct(int id)
{
Product product = db.Producten.Find(id);
return Mapper.Map<Product, Dto.Product>(product);
}

How to create a LINQ to Entities query including both tag class name and text string

My ASP.NET MVC project has some
chapter class
and related
tag class
They have many to many relationship though one tag has multiple chapter and also one chapter has multiple tags on it.
My question is: I want to make a query by using tag.title within this structure but LINQ doesn't allow objects; it only gets variables like string, int ...etc.
I am feeling a little bit stupid but I can't figured it out this basic thing :( (May be I have to give a break to let it be clear in my mind)
My models are:
public partial class Chapter
{
public string Id { get; set; }
public string Subject { get; set; }
public string Content { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public partial class Tag
{
public int? TagId { get; set; }
public string Title { get; set; }
public int CallCount { get; set; }
public virtual ICollection<Chapter> Chapters { get; set; }
}
and also for db:
public class DataContext : DbContext
{
public DbSet<Chapter> Chapters { get; set; }
public DbSet<Tag> Tags { get; set; }
}
so here we go:
var tag = (from t in db.Tags where t.Title.Contains(search_word)).FirstOrDefault();
var chapters = (from c in db.Chapters where (m.Title.Contains(search_word) || m.Tags.Contains(tag)) select c).ToList();
As I explained above; it gives
"you should use string, guid, int... on queries"
error for this query. I think there is a logical failure I made but my brain stopped responding...
Briefly; I want to search by tag names and if you have another approach I will be pleased to listen it..
Any help will be highly appreciated.
Thanks!
You want:
var tag = (from t in db.Tags
where t.Title.Contains(search_word)
select t).FirstOrDefault();
var chapters = (from c in db.Chapters
where m.Title.Contains(search_word)
|| m.Tags.Any(t => t.TagId == tag.TagId)
select c).ToList();

Entity Framework and Models with Simple Arrays

This is my model class.
public class Lead
{
private readonly ObservableCollection<String> m_tags = new ObservableCollection<string>();
public int LeadId { get; set; }
public string Title { get; set; }
public ObservableCollection<String> Tags { get { return m_tags; } }
}
Does Entity Framework offer a way to represent this using either Model-First or Code-First?
EDIT: I'm looking for a way to do this without changing the public API of the model. The fact that there is some sort of Tags table shouldn't be visible to the downstream developer.
Since your model has to be represented in a relational way, you can only use primitive types (that have an equivalent in a SQL DB) or other entities within a entity definition - that means the tags are represented by their own entity. In your case it would be something like this using Code first approach:
public class Lead
{
public int LeadId { get; set; }
public string Name { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public int TagId { get; set; }
public string Name { get; set; }
}
public class SomeContext : DbContext
{
public DbSet<Lead> Leads { get; set; }
public DbSet<Tag> Tags { get; set; }
}
This (by default) will be represented in the database as a table Leads, a table Tags, and a relationship table LeadTags that only contains {LeadId, TagId} pairs.