EF6 Too Many Navigation Properties Limitation - asp.net-mvc-5

I'm using E.F 6.2 code first in my MVC project and configure the project for using Asp.Net Identity 2 for accounting. I have a "BaseData" entity, that contains all of my basic data. Here is the class body:
Parent Entity:
public class BaseData
{
public int Id { get; set; }
public string Caption { get; set; }
public virtual ICollection<A> Children1 { get; set; }
public virtual ICollection<B> Children2 { get; set; }
.
.
.
public virtual ICollection<ZZZ> ChildrenN { get; set; }
}
So the other entities must be related to it. In my case, each child entity has hundreds of relations to the "BaseData" parent entity and I have hundreds of child entities. So there is thousands of relations to the parent entity. Here is the pseudo code for child entities:
Child Entities:
public class A
{
public int Id { get; set; }
public int BaseData1Id { get; set; }
public BaseData BaseData1 { get; set; }
public int BaseData2Id { get; set; }
public BaseData BaseData2 { get; set; }
.
.
.
public int BaseData300Id { get; set; }
public BaseData BaseData300 { get; set; }
}
.
.
.
.
public class ZZZ
{
public int Id { get; set; }
public int BaseData1Id { get; set; }
public BaseData BaseData1 { get; set; }
public int BaseData2Id { get; set; }
public BaseData BaseData2 { get; set; }
.
.
.
public int BaseData300Id { get; set; }
public BaseData BaseData300 { get; set; }
}
I'm using E.F fluent API to configure the relationship between my entities. The problem is that when I run the project and want to fetch some data like user account, I get the "StackOverFlow" exception !!
For solving the problem, I try to remove child entities one by one, and re-creating the database. I found that when the children decreases, the problem is solved and I didn't get exception but I don't know really why !!
Is there limitation for navigation properties on E.F ?
Is there a solution to increase the stack capacity for preventing "StackOverFlow" exception ?

Related

how to choose aggregate root

I model three entities in the auto industry as following:
public class Manufacturer
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Model> Models { get; set; }
public ACManufacturer()
{
AutoCareModels = new List<ACModel>();
}
}
public class Model
{
public int Id { get; set; }
public string Name { get; set; }
public int NumberOfSeats { get; set; }
public Manufacturer Manufacturer { get; set; }
public ICollection<ManufacturedYear> ManufacturedYears { get; set; }
public Model()
{
ManufacturedYears = new List<ManufacturedYear>();
}
}
public class ManufacturedYear
{
public int Id { get; set; }
public int ProductionYear { get; set; }
public Model Model { get; set; }
}
Please tell me how to choose aggregate root or the differente way to model three entities
Thank you every much
Answer depends on what you do with these models. What is your app doing? If 10 users are updating data in this app - how can they divide their work? What are transaction boundaries?
If those 10 users are usually working with 10 different models, your screens are organized around models, then Model is your aggregate root.

Automapper projection results in empty collection for nested Dto

I have a .Net Core 2 webapi in which I am using automapper to map to Dtos. Everything works fine, except I am seeing an unexpected behaviour when I map an object to a Dto, and where the Dto also contains mappings for a collection. E.g
CreateMap<Order, OrderDto>();
CreateMap<Product, ProductDto>();
Where classes are like this
public partial class Order
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products{ get; set; }
public int ProductCount {return Products.Count;}
}
public partial class Product
{
public int Id { get; set; }
public int OrderId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
The following works as expected;
The class is mapped, and the ProjectCount is correct in the Dto
public partial class OrderDto
{
public int Id { get; set; }
public virtual ICollection<Product> Products{ get; set; }
public int ProductCount{ get; set; }
}
_context.Orders.Include<>(Products).ProjectTo<>(OrderDto)
But doing the following, the productcount is always zero.
E.g. if I do this;
public partial class OrderDto
{
public int Id { get; set; }
public virtual ICollection<ProductDto> Products{ get; set; }
public int ProductCount{ get; set; }
}
public partial class ProductDto
{
public int Id { get; set; }
public int OrderId { get; set; }
public string Name { get; set; }
}
_context.Orders.Include<>(Products).ProjectTo<>(OrderDto)
Why does this happen, and how can I ensure that it doesnt? This is a real world example where I need a property which references the collection - and I need it in both the base and the Dto. I can do the following which works fine, but it doesnt appear that this should be how it works...
public partial class OrderDto
{
public int Id { get; set; }
public virtual ICollection<ProductDto> Products{ get; set; }
public int ProductCount {return Products.Count;}
}
public partial class ProductDto
{
public int Id { get; set; }
public string Name { get; set; }
}
_context.Orders.Include<>(Products).ProjectTo<>(OrderDto)
I profiled the SQL and found that Automapper changes the way the query is formed. Without the nested projection, two queries are made;
[Queries are more complex than this and use joins, but you get the idea]
Select Id from orders
Select Id,Name from products where productid in [select id from orders ]
With the nested projection, are executed for each nested Dto
Select Id from orders
Select Id,Name from products where id=1
Select Id,Name from products where id=2

Domain Driven Design Model

I am building ParkingReservation in DDD, In short means that people can invite place and when the car get in the camera identify the model and update the status of the place.
I divided the model to three Bounded contexts:
The first is Reservation Context that include the following objects:
`public class Lot
{
public int ID { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
public List<Place> Places { get; set; }
}
public class Place
{
public int ID { get; set; }
public int FloorNumber { get; set; }
public int RowNumber { get; set; }
public int ParkingNumber { get; set; }
}
public class Car
{
public int ID { get; set; }
public string Model { get; set; }
}
public class Driver
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public int Age { get; set; }
public Gender Gender { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public bool AcceptAdsToMail { get; set; }
public byte[] PictureData { get; set; }
public DateTime RegistrationTime { get; set; }
public DriverStatuses DriverStatuses { get; set; }
}
public class Reservation
{
public int ID { get; set; }
public Driver Driver { get; set; }
public Car Car { get; set; }
public Place Place { get; set; }
public DateTime OrderTime { get; set; }
public DateTime ParkingStartTime { get; set; }
public DateTime ParkingEndTime { get; set; }
public ParkingStatuses ParkingStatus { get; set; }
}
public class ParkingHistory
{
public int ID { get; set; }
public Place Place { get; set; }
public Driver Driver { get; set; }
public Car Car { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}`
The Parking Lot has list of places
the Driver reserve place through the application
the saved place saved in the Reservation object and when the parking time
elapsed, new parkinghistory added to parkinghistories list that belong to driver and car so you can watch history per car or driver.
for this context of Reservation:
(1) Is it correct to put Driver and Reservation for the Aggregate Roots? or maybe Lot too?
(2) Place is entity or value object?
Thank you
The main goal of your use case is scheduling. You need to think about a consistency boundary around that idea. To avoid time slots overlapping for a place in a lot you will need to create a new abstraction for the purpose.
"PlaceInLotReservations" sounds as a good option as an value object to serve as a factory for a Reservation aggregate. In order to represent reality of how scheduling works you should feed that aggregate in the context of a day, so "PlaceInLotReservationsRepository" should has a "findByDate" method that collects all Reservations for a place in a given datetime.
So the semantics would be something like:
val placeInLotReservations = PlaceInLotReservationsRepository.findBy(datetime)
val reservation = placeInLotReservations.reserveFor(car, driver, startingTime, endingTime)
ReservationsRepository.save(reservation)
If there are lot of reservations in a place and so race conditions you can even make the VO smaller by passing in day quarters instead of a day for the initial look up.
BTW, can and driver are VOs in the context of the Reservation aggregate (they are not aggregates).
You can also have the history by querying the Reservation repository, you donĀ“t need ParkingHistory.
Hope it helps.

EF Code First - Many To Many

I have a problem with devising a many to many relationship in code first. EF is creating the Junction table and associating the Fk's as I would expect, however when i try to access the User's MailingList collection, there are no entries.
I've implemented test data on Initialise via Seeding, the data is al present in the database.
I think the problem lies with the constructors for Users and MailingLists, but I'm uncertain. I want to be able to navigate the navigational property of User.MailingLists.
var user = db.Users.Find(1);
Console.WriteLine("{0}", user.EmailAddress); //This is Fine
Console.WriteLine("{0}", user.Address.PostCode); /This is Fine
foreach (MailingList ml in user.MailingLists) // this is 0
{
Console.WriteLine("{0}", ml.Name);
}
My model is below:-
public class User : IEntityBase
{
public User()
{
MailingLists = new List<MailingList>();
}
public int Id { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string EmailAddress { get; set; }
public DateTime? DateLastUpdated { get; set; }
public DateTime DateCreated { get; set; }
public bool IsDeleted { get; set; }
public virtual Address Address { get; set; }
public ICollection<MailingList> MailingLists { get; set; }
}
public class MailingList : IEntityBase
{
public MailingList()
{
Users = new List<User>();
}
public int Id { get; set; }
public string Name { get; set; }
public DateTime? DateLastUpdated { get; set; }
public DateTime DateCreated { get; set; }
public bool IsDeleted { get; set; }
public ICollection<User> Users { get; set; }
}
public class Address : IEntityBase
{
public int Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
public string City { get; set; }
public string County { get; set; }
public string PostCode { get; set; }
public DateTime? DateLastUpdated { get; set; }
public DateTime DateCreated { get; set; }
public bool IsDeleted { get; set; }
}
Any suggestions welcome.
You are neither eager loading the MailingList entries with the query, nor fulfulling the requirements for a lazy loading proxy so there is no way EF can populate the collection.
To allow lazy loading, change the MailingList property to be virtual to allow the EF proxy to override it.
To use eager loading, use Include() (an extension method in System.Data.Entity) in the query to specify that the MailingList should be loaded.

EF - Lost In Migration

Before the migration I had an 1 to many relationship between tables Work and Factory:
public class Work
{
public int WorkId { get; set; }
public string Name { get; set; }
public virtual List<Factory> MyFactory { get; set; }
}
and:
public class Factory
{
public int FactoryId { get; set; }
public string Name { get; set; }
public virtual Work ParentWork { get; set; }
}
Then I tried to change the relationship to be an 1 to 1:
public class Work
{
public int WorkId { get; set; }
public string Name { get; set; }
[Required]
public virtual Factory MyFactory { get; set; }
}
public class Factory
{
public int FactoryId { get; set; }
public string Name { get; set; }
public virtual Work ParentWork { get; set; }
}
When I tried to create the migration with:
add-migration MyMigration
I received the following error:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.Work_dbo.Factory_WorkId". The conflict occurred in database "EntityFrameworkLab.MyContext", table "dbo.Factory", column 'FactoryId'
Now, I have a few questions:
1) Why couldn't the migration be created, whereas the model is valid?
2) What changes should I implement in the code?
3) If I try to manually revert the changes, the same error message occurs, but this time when I try to do the:
update-database -verbose

Resources