Entity Framework - Persistence Model different from Domain Model - c#

I have following lagacy code. There is a seperation between Pesistence Model and the (anemic) Domain Model. What is the benefit of this seperation and the implicit conversion ? Do you see any drawbacks ?
I know that with implicit conversion following is possible:
SplitAmountEF saEF = dbContext.SplitAmount.Find(id);
SplitAmount sa = saEF; //implicit conversion.
They can be used interchangeable.
If the domain model is almost the same like persistence model, wouldnt it be better to use only the persistence model (without using Domain Model at all)?
Example:
//Domain Model
public class Booking
{
public Guid ID {get; set;}
....
}
public class SplitAmount
{
public Guid ID {get; set;}
public Decimal Amount {get; set;}
...
public Guid IDBooking {get; set;}
}
//Persistence Model
public class BookingEF
{
public Guid ID {get; set;}
...
}
public class SplitAmountEF
{
public Guid ID {get; set;}
public Decimal Amount {get; set;}
...
public virtual BookingEF Parent {get; set;}
//implicit converstion from SplitAmountEF to SplitAmount
public static implicit SplitAmount(SplitAmountEF saEF)
{
return new SplitAmount()
{
ID = saEF.ID,
Amount = saEF.Amount,
...
IDBooking = saEF.Parent.ID,
}
}
//implicit converstion from SplitAmount to SplitAmountEF
public static implicit SplitAmountEF(SplitAmount sa)
{
return new SplitAmountEF()
{
ID = sa.ID,
Amount = sa.Amount,
...
}
}
}

Related

Can you have AutoMapper only map properties that match explicitly

Is there a way to have AutoMapper only map properties that match explicitly? My Model has a property UserAccountId and also has a navigation property UserAccount that has an Id property, if the user posts UserAccountId, I want AutoMapper to map UserAccountId and leave UserAccount.Id null; I'd love to avoid using Ignore since that will prevent me from explicitly posting UserAccount.Id as well. I can't find any information on controlling AutoMapper's name matching strategy...
public class Role {
public int Id {get; set;}
public int UserAccountId {get; set;}
public UserAccount UserAccount {get; set;}
...
}
public class UserAccount {
public int Id {get; set;}
...
}
public class RoleViewModel {
public int Id {get; set;}
public int UserAccountId {get; set;}
}
public ActionResult AddRole(RoleViewModel viewModel) {
var model = GetModel(viewModel.Id);
Mapper.Map(viewModel, model);
//Do not infer and map UserAccount.Id
}
Don’t use AutoMapper for this case. It wasn’t built to support this type of scenario.
Or use ForPath(...).Ignore, but I just wouldn’t use my library for this scenario.

How to avoid circular references with AutoMapper?

I have the following models (and corresponding DTOs):
public class Link
{
public int Id {get; set;}
public int FirstLinkId {get; set;}
public int SecondLinkId {get; set;}
public virtual Link FirstLink {get; set;}
public virtual Link SecondLInk {get; set;}
}
public class OtherObject
{
public int Id {get; set;}
public int LinkId {get; set;}
public string Name {get; set;}
public virtual Link Link {get; set;}
}
In my scenario, I can have a Link object where FirstLink and/or SecondLink can be null, references to other objects, or references to the same object.
Now I want to load an OtherObject entity from the db using EF. I load the entity itself and also the Link object associated with it. This is done perfectly by EF.
In this particular case, both FirstLink and SecondLink are the same as Link, therefore, when automapping from model to dto it just keeps on mapping into oblivion.
My mapping is:
Mapper.CreateMap<OtherObject, OtherObjectDto>().Bidirectional()
.ForMember(model => model.LinkId, option => option.Ignore());
where Bidirectional() is this extension:
public static IMappingExpression<TDestination, TSource> Bidirectional<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
return Mapper.CreateMap<TDestination, TSource>();
}
Is there way to tell Automapper not to map further down the tree in this case?
The way I would handle this is to create separate DTO objects for the children:
public class Employee
{
public int Id {get; set;}
public string Name { get; set; }
public Employee Supervisor {get; set; }
}
public class EmployeeDto {
public int Id {get; set;}
public string Name { get; set; }
public SupervisorDto Supervisor { get; set; }
public class SupervisorDto {
public int Id {get; set;}
public string Name { get; set; }
}
}
Mapper.CreateMap<Employee, EmployeeDto>();
Mapper.CreateMap<Employee, EmployeeDto.SupervisorDto>();
Don't let your DTOs be recursive/self-referential. Be explicit in your structure on how deep you want it to go.
EF can't do recursive joins, you're only doing one level, so don't make your DTOs go nuts with infinitely deep relationships. Be explicit.

Should foreign Id properties be mapped from Model to Dto?

If I have the following model:
public class Customer
{
public int Id {get; set;}
public int CustomerTypeId {get; set;}
public virtual CustomerType {get; set;}
}
Should the Dto exclude foreign Id's to look like this:
public class CustomerDto
{
public int Id {get; set;}
public virtual CustomerType {get; set;}
}
And when using Graphdiff to update the object graph, will EF know that CustomerType maps to CustomerTypeId?
Yes, you need to use it but you can avoid virtual member declaration. If you use AutoMapper, then the mapping will be done automatically. So, your Dto will look like this:
public class CustomerDto
{
public int Id {get; set;}
public int CustomerTypeId {get; set;}
}
And the mapping:
Mapper.CreateMap<Customer, CustomerDto>();
Mapper.CreateMap<CustomerDto, Customer>();

Is there any way to use OData $orderby on complex type?

Example:
public class Address
{
public string Address1 {get; set;}
public string Address2 {get; set;}
}
public class User
{
public int Id{get; set;}
//Complex type
public Address Address{get; set;}
}
I have a grid that is fill with data of User. I want to make $orderby by Address, is this posible?
Maybe you should use the List object:
public class AddressObject
{
public string Address {get; set;}
}
public class User
{
public int Id {get; set;}
public List<AddressObject> adressList = new List<AddressObject>();
}
Than you can order with LINQ:
var orderedAdressList = adressList.OrderBy(z => z.Address)

Entity framework and Classes

I am trying to learn Entity framework. Say, I have the following classes
class Course
{
[Key]
public virtual int CourseID {get; set;}
public virtual string CourseName {get; set;}
}
class CourseDBContext:DBContext
{
public DbSet<Course> Courses{get;set;}
}
Then I can use Linq to query the database as shown below
using (CourseDBContext a = new CourseDBContext())
{
var b = from c in a.Course
where c.CourseID == 1001
select c;
var d = b.FirstOrDefault();
if(d != null)
Console.WriteLine(d.CourseName);
}
This works fine. Now if I add a second class
class Assignment
{
[Key]
public virtual int CourseID {get; set;}
public virtual int StaffID {get; set;}
}
class AssignmentDBContext:DBContext
{
public DbSet<Assignment> Assignments{get;set;}
}
Now, How can I use Linq to select and display the CourseName and StaffID associated with CourseID = 1001?
The example above is contrived and so the table design and fields are irrelevant. I just want to know how to query the data between two classes from two different database tables using Entity Framework and Linq.
Thanks
Both entities need to be in the same context.
public class CoursesContext: DbContext
{
public DbSet<Assignment> Assignments {get; set;}
public DbSet<Course> Courses {get; set;}
}
You can add an Assignment navigation property to filter on a foreign key:
public class Course
{
[Key]
public virtual int CourseID {get; set;}
public virtual string CourseName {get; set;}
public virtual Assignment {get; set;}
}
Then you can query like so:
var staffId =
from c in a.Course
where c.CourseID == 1001
select c.Assignment.StaffID;
Don't have a seperate context for each DbSet. I.e
class MyDbContext : DBContext
{
public DbSet<Course> Courses{get;set;}
public DbSet<Assignment> Assignments{get;set;}
}

Categories