Mapping Business Object to multiple Database Tables - c#

I am migrating /re-developing a web app from JavaScript to the ASP.NET MVC Framework using C#/ JS (with Handlebars.NET) for my Bachelor thesis.
So far I have created a Web.API and the actual app with a form.
In the app I enter details to create a new Employee, which is then Posted to the API, which receives that Json-Object as a "Business Object" BOEmployee.
Said BOEmployee looks like this (simplified):
public class BOEmployee
{
public int ID_Employee { get; set; }
public int ID_Company { get; set; }
public string lastName { get; set; }
public string firstName { get; set; }
}
I want to map this object to two other objects, representing tables of the underlying database, to then save them to the database. The two target tables are auto generated with Entity Framework.
Here are the table objects:
1. Employee:
public partial class Employee
{
public int ID_Employee { get; set; }
public int ID_Company { get; set; }
}
2. Employee_Details:
public partial class Employee_Detail
{
public int ID_Employee_Detail { get; set; }
public int ID_Employee { get; set; }
public string lastName { get; set; }
public string firstName { get; set; }
}
Now I could map them manually by assigning every attribute but clearly that is a horribly unsustainable idea. So I was looking for a way to automate that mapping process automatically using Json.Net like this:
[HttpPost]
public BOEmployee SaveEmployee([FromBody] string employee)
{
using (var context = new myDBEntities())
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
Employee_Detail dbEmployeeDetails = serializer.Deserialize<Employee_Detail>(BOEmployee);
Employee dbEmployee = serializer.Deserialize<Employee>(BOemployee);
}
}
Now what happens when I run that code is, that the serializer-function complains that the input values cannot be null, which to my understanding is because the target Objects (e.g. Employee) do not have all attributes that are given in the serialized Json-Object.
The Error Message is this:
Value cannot be null.\r\nParameter name: input",
"ExceptionType":"System.ArgumentNullException"
Now my question would be, how can I map my object to the different Database tables? Or am I completely on the wrong path now?
Fundamental changes to the program structure cannot be made any more due to available time (and I am basically a complete beginner in programming).

I recommend AutoMapper than what you are using there.

Related

Is is good practice to have same type of list in a class?

I have created a class and I'm putting a list of same type as a property of that class.
Is it good or bad practice?
I am putting the same type of list because of I want to manage everything by only one object.
I don't want to create a single object and a list of object of the same type.
Any help is highly appreciated!
class AssetSection
{
public string Code { get; set; }
public string Description { get; set; }
public string SITEID { get; set; }
public string PlantID { get; set; }
public string User { get; set; }
public string UpDateTime { get; set; }
public List<AssetSection> AssetSections { get; set; }
public AssetSection(string des, string code)
{
Description = des;
Code = code;
}
}
That's ok. If you can imagine, you can design and use it.
Let's talk about entity framework. We create 2 entities like this:
public class User : IdentityUser
{
[Key]
public string Id { get; set; }
public UserProfile Profile { get; set; }
}
public class UserProfile
{
[Key]
public string UserId { get; set; }
public User User { get; set; }
}
Now, when we try to get current user:
User user = await _userManager.GetUserAsync(User);
user becomes an instance of User class now. This instance has a property name Profile, and this property has another property name User which has a type User.
It's called mapping. So, to answer your question: You can use it. But I'm not saying it's good or not based on the way to design the model.
As a general observation, such a structure is known as a rose tree, or just a tree. It enables you to write code like this:
var t = new AssetSection("foo", "bar")
{
AssetSections = new List<AssetSection>
{
new AssetSection("baz", "qux")
{
new AssetSection("corge", "garply"),
new AssetSection("fred", "plugh")
{
AssetSections = new List<AssetSection>
{
new AssetSection("xyzzy", "thud")
}
}
},
new AssetSection("quux", "quuz")
{
new AssetSection("grault", "waldo")
}
}
};
If what you want to model is a tree-like structure like that, then it's fine. On the other hand, if such a hierarchy is not what you're trying to model, then it's likely to be confusing.
By the way, the code as proposed violates the .NET framework design guidelines:
DO NOT provide settable collection properties.
DO NOT use ArrayList or List<T> in public APIs

Entity Framework Core 2.0: One-To-Many-Relationship only works once

I'm using ASP.NET Core 2.0 with Angular-Frontend and Entity Framework Core 2.0. I have following DbSets: DbSet<Vocabulary> Vocabularies and DbSet<Word> Words, while the class Vocabulary contains a collection of words: List<Word> Words { get; set; }. In my API-Controller I've written a method which provides the vocabularies to the frontend as a response to an HTTP-Get-request. To test my database-connection and everything, I used the same method to create an initial record into my database:
[HttpGet]
public IEnumerable<Vocabulary> Get()
{
if (!Context.Vocabularies.Any())
{
Context.Vocabularies.Add(new Vocabulary
{
Name = "MyVocabulary",
Words = new List<Word>
{
new Word
{
PrimaryLanguage="Test",
SecondaryLanguage="Test",
Score= 0
}
}
});
Context.SaveChanges();
}
return Context.Vocabularies;
}
Now, the weird thing is that when the DB is empty, everything works as expected. When I reload the page (or restart the local IIS) and the HTTP-GET-request happens again, I get all vocabularies with correct ID's etc. but the property Words is null... I'm using a local SQL Server database. The tables seem ok, the words have the correct VocabularyId.
I just found out that there's a method called Include(). Tried it the following way: return Context.Vocabularies.Include(v => v.Words);, but didn't work either.
Vocabulary.cs:
public class Vocabulary
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Word> Words { get; set; }
}
Word.cs:
public class Word
{
public int Id { get; set; }
public string PrimaryLanguage { get; set; }
public string SecondaryLanguage { get; set; }
public double Score { get; set; }
}
Any ideas?
I believe that you have not fully defined the relationship between the two models. Based on this documentation
Relationships
You are missing the link from Word back to Vocabulary. Adding this to the Word class should solve it:
public int VocabularyId {get; set; }

DB update randomly throwing Validation Error MVC 4 EF

So I have a controller which updates just 2 fields in a db entry, however that entry is linked to two other tables, I know it's a bad explanation but sometimes it works and sometimes it doesn't and I cant identify what's different between submissions since no code changes.
Error
Controller
GroupFitnessSession session = unitOfWork.GroupFitnessSessionRepository.GetById(item.GroupFitnessSessionId);
session.IsConfirmed = true;
session.Attendees = item.Attendees;
unitOfWork.GroupFitnessSessionRepository.Update(session);
There are other fields to the Models that i've left out, but non of them are the same name or something to these oens
Models
public class GroupFitnessSession
{
public string GroupFitnessSessionId { get; set; }
[Required]
public virtual Trainer Trainer { get; set; }
[Required]
public virtual Location Location { get; set; }
}
public class Location
{
public string LocationId { get; set; }
public Location()
{
GroupFitnessSession = new HashSet<GroupFitnessSession>();
}
public ICollection<GroupFitnessSession> GroupFitnessSession { get; set; }
}
public class Trainer
{
public Trainer()
{
GroupFitness = new HashSet<GroupFitnessSession>();
}
public ICollection<GroupFitnessSession> GroupFitness { get; set; }
If you need any other information feel free to ask.
This is just confusing me too much, any advice would be appceiated
EDIT: showing that Location and Trainer are not empty objects
As you can see the auto generated Properties from EF aswell as the propertiy I am trying to update
This will work if you change the first line of the controller to:
GroupFitnessSession session = unitOfWork.GroupFitnessSessionRepository.GetById(item.GroupFitnessSessionId).Include(s => s.Trainer).Include(s => s.Location);

C# (Web API) Multilayer (IOC) API Controller Return Type

I am building an ASP Web API application and this time I thought I will go with the MVC pattern. I got along with most of the stuff, but there is one thing of which I am unsure. First of all my project consists of the following:
Data Layer
Business Layer
Model Layer (just the model with the properties)
Service Application (here are my controllers)
every one of them in a separate project
Lets say I have the following controller
public class TestController : ApiController
{
ISomeService _someBusiness;
public TestController(ISomeService someBusiness)
{
_someBusiness = someBusiness;
}
public **SomeModelObject** GetModelObject(ind id)
{
return _someBusiness .GetSomeModelObject(id);
}
}
Now my problem is the return value of GetModelObject(int id). Here it says SomeModelObject. That implies that my Service application (or my controller) has to know everything about the model which is being used (so I dont see the point in defining it in a separate .dll). One way would be to define the model (precisely the get/set mothods) as an interface, but I think that it would be too much that every model class has an interface (mostly because, as I said, just the properties are being stored inside the model), and despite that I just does not feel right to build an interface for a class which only stores data. So, is there any generic response type which is being used in this case (even some completely different approach), or do I have to use my model classes (or may i just always use string and it is being converted to the appropriate format by the client) ?
There's a good reason to use an interface to hide the complexity of the model object. It holds data, sure. But it holds unnecessary data that is only meaningful to the data layer. Take this EF model:
public class Employee
{
public int Id { get; set; }
public string EmployeeNumber { get; set; }
public string Name { get; set; }
public virtual Collection<TimeCard> TimeCards { get; set; }
public int DepartmentId { get; set; }
public virtual Department Department { get; set; }
}
This is a fairy common EF model. It contains a surrogate key Id, and a foreign key DepartmentId. Those values are meaningless except for the database and, by extension, for entity framework. EmployeeNumber is the natural key which uniquely identifies the entity in the user's domain.
Outside of database access, you should really only deal with natural data values. You could do this by declaring yet another data-carrying class in the Business layer and perform mapping, or a better idea is to use an interface to hide all of the members that are not useful.
public interface IEmployee
{
string EmployeeNumber { get; }
string Name { get; set; }
ICollection<ITimeCard> TimeCards { get; }
IDepartment Department { get; set; }
}
Notice the lack of some setters in the interface. You'll never want to change the EmployeeNumber because that is the natural key for the entity. Likewise, you'll never assign a collection object to the TimeCards property. You'll only ever iterate over, add, or remove them.
Now your Employee class becomes
public class Employee : IEmployee
{
public int Id { get; set; }
public string EmployeeNumber { get; set; }
public string Name { get; set; }
public virtual Collection<TimeCard> TimeCards { get; set; }
ICollection<ITimeCard> IEmployee.TimeCards { get { return TimeCards; } }
public int DepartmentId { get; set; }
public virtual Department Department { get; set; }
IDepartment IEmployee.Department { get { return Department; } set { Department = value; } }
}
In your business layer and above, you'll only use variable of IEmployee, IDepartment, and ITimeCard. So you are exposing a tighter API to the higher layers, which is a good thing.
You could try to use a generic approach at controller level:
public class BusinessController<T> : ApiController
{
ISomeService _someBusiness;
public TestController(ISomeService someBusiness)
{
_someBusiness = someBusiness;
}
public T GetModelObject(ind id)
{
return _someBusiness.GetSomeModelObject(id);
}
}
Finally your controlers inherit from BusinessController instead of ApiController:
public class TestController : BusinessController<SomeModelObject>
{
}
You could also take advance of the templating to inject the right "ISomeService" by using an IoC container and a bootstrapper.

ASP.Net MVC POST data not mapping to model

I'm trying to build a model to receive data from a HTTPPOST.
The model is received and populated fine - except for IList<harsta> harequest
It shows as having a count of 1, but having null values against the fields:
My model is:
public class HAR
{
public int api_version { get; set; }
public IList<harsta> harequest { get; set; }
public class harsta
{
public int ta_id { get; set; }
public string partner_id { get; set; }
public string partner_url { get; set; }
}
...
...
}
The Post data for harrequest is (should have 2 entries):
[{"ta_id":97497,"partner_id":"229547","partner_url":"http://partner.com/deeplink/to/229547"},
{"ta_id":97832,"partner_id":"id34234","partner_url":"http://partner.com/deeplink/to/id34234"}]
A screenshot from PostMan shows the form encoded data that is sent to the controller:
Example Request (this is the example provided on the 3rd party website)
POST
http://partner-site.com/api_implementation/ha
BODY
api_version=4
&harequest=[{"ta_id":97497,"partner_id":"229547","partner_url":"http://partner.com/deeplink/to/229547"},{"ta_id":97832,"partner_id":"id34234","partner_url":"http://partner.com/deeplink/to/id34234"}]
&start_date=2013-07-01
...
&query_key=6167a22d1f87d2028bf60a8e5e27afa7_191_13602996000
I'm sure it's not mapping to my model, because of the way I've setup my model here:
public IList<harsta> harequest { get; set; }
public class harsta
{
public int ta_id { get; set; }
public string partner_id { get; set; }
public string partner_url { get; set; }
}
Have I setup the model incorrectly, to receive the JSON data from the harequest field in the POST?
First of all, I'm not exactly comfortable with the embedding of the Harsta class in the Har class. Not good practice separate them.
Secondly, I think your problem actually stems from the fact the property names in the JSON object(s) you are returning are enclosed in quotes. Get rid of the quotes for only the property names.
That is don't do this:
[{"ta_id":97497,"partner_id":"229547","partner_url":"http://partner.com/deeplink/to/229547"},
{"ta_id":97832,"partner_id":"id34234","partner_url":"http://partner.com/deeplink/to/id34234"}]
Do this instead:
[{ta_id:97497,partner_id:"229547",partner_url:"http://partner.com/deeplink/to/229547"},
{ta_id:97832,partner_id:"id34234",partner_url:"http://partner.com/deeplink/to/id34234"}].

Categories

Resources