I would like to use DTOs and AutoMapper to POST and PUT an entity containing a List of nested entities, having a hierarchy.
Sample :
A company has a list of employees. In this list of employees can have a manager which is also an employee of the same company.
public class Company {
public int Id { get; set; }
public List<Employee> Employees { get; set; }
}
public class Employee {
public int Id { get; set; }
public Company Company { get; set; }
public int CompanyId { get; set; }
public Employee Manager { get; set; }
public int? ManagerId { get; set; }
}
I'd like to create a DTO which is able to POST and UPDATE a Company creating/updating/removing and changing relations between employees.
How would you do knowing that some employees can have no Id yet because they are newly created but are parents of other employees ?
Thanks in advance for the help.
Precision : i use dot net core 2.2, Entity Framework Core and AutoMapper.
You can do this as below.
public class CompanyDto {
public int Id { get; set; }
//Below line cannot exist here, otherwise it will create circular references
//public List<Employee> Employees { get; set; }
}
public class EmployeeDto {
public int Id { get; set; }
public Company Company { get; set; }
public int CompanyId { get; set; }
public Employee Manager { get; set; }
public int? ManagerId { get; set; }
}
After this, you can create your mappings in automapper configuration for Company -> CompanyDto(and reverse map) and Employee to EmployeeDto(and reverse map).
Now, for handling the case of new manager with existing employee, you do either of the following in your repository(with entity objects, not DTO's)
Create a new employee and then update the existing employees with the newly generated employee id in your repository
Or, get all the employees you want to update in your repository(load in context), add the new employee in the context with EntityState.Added. Now, assign the manager of employees you have fetched with the reference of new employee and save your context
Related
If you need to create one View from various entity (models), is it best to create a separate class as a ViewModel containing the specific properties that you need or is it better to create another entity with the specific properties and associate that entity with the rest of the entities in the ORM designer?
You can merge any number of models into one model by declaring them a property of the main m odel. Suppose that you have the following models:
public class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int SchoolID { get; set; }
public virtual School StudentSchool { get; set; }
}
public class School
{
public School()
{
this.Students = new HashSet<Student>();
}
public int SchoolID { get; set; }
public string ASchoolName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
If you just set the Student class as your view model, you can retrive the School of your student and in this case you doesn't need to do anything.
However we suppose that you also need all schools and all students in your view as your view model. To do this, create another class and add the above classes as its properties:
public class MyModel
{
List<Student> MyStudents { get; set; }
List<School> MySchools { get; set; }
}
You can create any complex model you need by this approach...
I an fairly new to MVC, and have created an MVC4 application using EF-database-first. The database does not contain foreign key definitions and I can't add them (I don't own the database). Here are two example classes from the database:
public partial class Allocation
{
public int AllocID { get; set; }
public int DeptID { get; set; }
public decimal AllocationPercent { get; set; }
}
public partial class Department
{
public int DeptID { get; set; }
public string DeptName { get; set; }
public string Account { get; set; }
}
The default Allocation Index page shows the department ID. I want to show the department name instead. How can I do this without navigation properties?
I tried
public class AllocationController : Controller
{
private Entities db = new Entities();
//
// GET: /Allocation/
public ActionResult Index()
{
return View(db.Allocation.Include(d => d.DeptID).ToList());
}
...
but this gives an error ("A specified Include path is not valid. The EntityType 'TESTModel.Allocation' does not declare a navigation property with the name 'DeptID'.")...
I'm not sure how to code eager-loading or explicit-loading without navigation properties either, which prompted this question. Efficiency-wise, I don't believe it matters which way I load the related information, so any help in any direction would be appreciated.
The database does not have to have definitions, as long as the fields are there and the entities have been placed in the database with referential integrity in mind. All you need to do is let entity framework know about the relationship. This is done with the virtual keyword to create "Navigational Properties".
public partial class Allocation
{
public int AllocID { get; set; }
public int DeptID { get; set; }
public decimal AllocationPercent { get; set; }
public virtual Department Department { get; set; } /* this is your nav property */
}
public partial class Department
{
public int DeptID { get; set; }
public string DeptName { get; set; }
public string Account { get; set; }
}
Now you can do:
db.Allocation.Include(a => a.Department).ToList()
There may be an error which requires you to use a foreign key definition (although I do not think so). If this is the case, you will need to decorate your navigation property like this
[ForeignKey("DeptID")]
public virtual Department Department { get; set; }
You may also try it this way:
public int AllocID { get; set; }
[ForeignKey("Department")]
public int DeptID { get; set; }
public decimal AllocationPercent { get; set; }
public virtual Department Department { get; set; }
With navigation properties, Travis J's answer is what you need.
If you don't want to use navigation properties, assuming your DB context has a set called Departments, you could do smth like this:
var deptId = db.Allocation.DeptID;
var departments = db.Departments.Where(p => p.DeptID == deptId);
return View(departments.ToList());
Scenario seems to be trivial and I'm really confused on what I'm doing wrong.
So, I have a Client class
public class Client
{
[Key]
public int ClientID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual Account Account { get; set; }
}
Employee class
public class Employee
{
[Key]
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual Account Account { get; set; }
}
and an Account class
public class Account
{
[Key]
public int AccountID { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public virtual Employee Employee { get; set; }
public virtual Client Client { get; set; }
}
Both Client and Employee may have an Account or not ( online access is optional ). As database is not compatible with EF namingconvention I have to come up with Fluent API explicit mappings.
Both Client and Employee tables have "AccountID" column that I'm trying to use to build a relation.
modelBuilder.Entity<Client>()
.HasOptional(e => e.Account)
.WithRequired(a => a.Client)
.Map(m => m.MapKey("AccountID"));
modelBuilder.Entity<Employee>()
.HasOptional(e => e.Account)
.WithRequired(a => a.Employee)
.Map(m => m.MapKey("AccountID"));
but I get
Schema specified is not valid. Errors:
(15,6) : error 0019: Each property name in a type must be unique. Property name 'AccountID' was already defined.
(16,6) : error 0019: Each property name in a type must be unique. Property name 'AccountID' was already defined.
so, is there a way to fix this other than modification of the table/entity structure?
Turns out you don't need Fluent API in this case, what you need is to DataAnnotate your properties in Entities with InverseProperty attribute
[InverseProperty("AccountID")]
There is a great answer by Ladislav Mrnka in Entity Framework 4.1 InverseProperty Attribute question
However if anyone knows how to do that correctly with Fluent answers are highly appreciated
I'm working on a legacy MySql database and have the following entities:
public class Company
{
public int Id { get; set;}
public string Address { get; set; }
public string City { get; set; }
}
public class CompanyDepartment
{
public int Id { get; set;}
public string Address { get; set; }
public string City { get; set; }
}
The idea is that a company only use the department class if it has more than one department.
Right now I'm trying to make a company/department search, this means I need a list of all departments and therefore I need to "create" departments of all the companies that only has one department, and therefore don't have a entry in CompaynyDepartment.
To do this I was thinking of use components in fluent NHibernate, but I'm not sure I can join the real departments with the fake ones?
Is there a better approach to this problem? It's not an option to change the database structure.
I ended up changing the database structure
I have a problem using QBE with NHibernate. I have a one-to-one relationship between a Person class and an Employee.
public class Person
{
public virtual Employee Employee { get; set; }
public virtual int Age { get; set; }
public virtual string Forename { get; set; }
public virtual string Surname { get; set; }
public virtual int PersonID { get; set; }
}
public class Employee
{
public virtual int PersonID { get; set; }
public virtual string PayRollNo { get; set; }
public virtual int Holidays { get; set; }
public virtual Person Person { get; set; }
}
As an example, I want to get all Employees where Employee.Forename="John" and Employee.Person.PayRollNo = "231A". I was wondering if I could use Query By Example to do this?
I have not been able to find a definitive "no" but I haven't been able to get this work. I've found that QBE is promising but unfortunately not very useful due to the following limitations:
Cannot query related objects.
Requires public parameterless constructor.
Initialized properties are included in query unless specifically excluded using ExcludeProeprty. For example, bool properties are restricted to false in the where clause, DateTime as DateTime.MinValue. This makes the query very brittle because class modifications may have bad side effects.