Navigation property doesn't get loaded - EF - c#

I'm having 3 models Items, Branches and ItemsInBranches defined as follows
public class Items
{
public int Id { get; set; }
public string Barcode { get; set; }
public string Name { get; set; }
public int SizeId { get; set; }
public int Price { get; set; }
public int DiscountId { get; set; }
public int ShortageMargin { get; set; }
[NotMapped]
public double ActualPrice
{
get
{
double amount = ((double)Price * (double)Discount.Amount / 100);
double price = (Price - amount < 0) ? 0 : Price - amount;
return price;
}
}
public Discounts Discount { get; set; }
public ItemSizes Size { get; set; }
public ICollection<ItemsInBranches> ItemsInBrach { get; set; }
}
public class Branches
{
public int Id { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public ICollection<Employees> Employees { get; set; }
public ICollection<TransactionLog> TransacionLogs { get; set; }
public ICollection<ItemsInBranches> ItemsInBranch { get; set; }
}
public class ItemsInBranches
{
public int Id { get; set; }
public int ItemId { get; set; }
public int BranchId { get; set; }
public int Amount { get; set; }
[NotMapped]
public bool IsShort
{
get
{
return Amount < Item.ShortageMargin;
}
}
public Items Item { get; set; }
public Branches Branch { get; set; }
}
whenever I try to load items in branches using the following code I Branch navigation property gets loaded just fine but I the Items is always set to null
public IEnumerable<StorageViewModel> GetStorage(int? BranchId)
{
var storage = Find(x => true).Select(s => new StorageViewModel
{
Amount = s.Amount,
BranchName = s.Branch.Name,
ItemName = s.Item.Name,
SortageMargin = s.Item.ShortageMargin,
IsShort = s.IsShort
});
return storage;
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return _dataContext.Set<TEntity>().Where(predicate);
}
I made sure the ItemId and BranchId are set to foreign keys for the Items and Branches tables in the database, they don't allow nulls and they enforce foreign key constraints
could anyone tell me why only the Branch get loaded while Item is always set to null

Generally you shouldn't try to wrap frameworks, particularly EF with helper methods like you're doing with your Find method, which I mention because that is why you're running into this problem (rather it's making the solution harder than it would otherwise have to be without the helper).
You may run into this problem you ran into (or where you want to specify AsNoTracking() in your Find one day when you find out about the ChangeTracker and how it works and SaveChanges() starts running slow or you have a large memory footprint due to having too much attached at once. Of course this is problem more with EF because it makes it too easy for people to develop without really understanding important concepts like transactions - the details of the layer it's trying to abstract away...)
You would need to load related entities somehow. I'd recommend reading this link and choosing an option. Here's one option on that link that only touches your GetStorage method, which might "solve the problem easily" but may not be good performance-wise if there are a lot of records - considering your predicate is including everything, though, there may not be a lot. I can't give you a better recommendation without seeing more of your code. If it's loading one and not the other and they're otherwise identical (same non-nullable FK and there's a corresponding record) then I think it's probably configuration somewhere... again read the link to see how to configure loading of navigation properties. Note this will probably generate multiple SELECT statements; I couldn't think of a better way (besides dropping down into Set<>) with the constraints of using Find inside GetStorage to grab the missing records you needed. If you could call the Find from a different class that has a different TEntity specified then you could probably get just the Items records you need in one SELECT statement - but I don't know how you're setting up your services and their lifecycles. That might be a compromise between performance and not having a mass-refactoring of the data access wrappers.
var allEntities = Find(x => true).ToList();
allEntities.ForEach(x => _dataContext.Entry(x).Reference(y => y. Item).Load());
var storage = allEntities.Select(s => new StorageViewModel
// ...
GetStorage seems like it's specific to one TEntity; Your Find method seems like it has TEntity defined as a generic in the containing class - so if I had to guess those methods are in (2) different classes even though you put them back-to-back. Your Find method is then probably on a class that abstracts away EF to give you a "simpler" interface to the database. EF is already that simple interface to the database; you don't need another.
What you could be doing instead is making concrete repositories that take a hard dependency on specific TEntity's and depend on a DbContext and then having either your domain logic taking a dependency on your repositories (which would require you to mock the repository somehow - either with a pseudo database, actual database or a leaky in-memory database to "unit" test your domain logic) or having your repositories totally de-coupled from your domain logic, enabling fast-executing domain logic unit tests. Then your repositories have shielded the rest of the application from EF, so you could change it out to ADO.NET or a lighter weight ORM like Dapper.
A Find method like that is an EF abstraction - you've tied whatever depends on that to EF (and your schema, probably) even if you didn't realize it. What I briefly described is true a database abstraction - which actually would free you up to change your data access (and schema) if you needed to - just change out the repository implementation without changing its API or behavior...

Related

Fastest and efficient way to get record using Entity Framework and C#?

I am beginner and I am using a function which takes approximately 20 seconds to load a record - please is there any other, more efficient and faster way to execute this? How i can include guest id with guest name so that its works faster rather then use for each loop to assign guest name with guest id
Data.Tables.Booking
[Table("Bookings")]
public class Booking : ITrackable
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int GuestId { get; set; }
public int RoomId { get; set; }
public DateTime CheckInDateTime { get; set; }
public DateTime CheckOutDateTime { get; set; }
public decimal DailyPricePerBed { get; set; }
[StringLength(1000)]
public string Memo { get; set; }
public string PriceType { get; set; }
public bool Paid { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime ChangedAt { get; set; }
public string? InvoiceType { get; set; }
}
Booking model
public class Booking : BaseModel
{
[Required]
public int Id { get; set; }
[Required(ErrorMessage = Constants.ERROR_REQUIRED)]
[Display(Name = "Gast")]
public int GuestId { get; set; }
[Required(ErrorMessage = Constants.ERROR_REQUIRED)]
[Display(Name = "Zimmer")]
public int RoomId { get; set; }
[Required(ErrorMessage = Constants.ERROR_REQUIRED)]
[Display(Name = "Check-In")]
public DateTime CheckInDateTime { get; set; }
[Required(ErrorMessage = Constants.ERROR_REQUIRED)]
[Display(Name = "Check-Out")]
public DateTime CheckOutDateTime { get; set; }
[Required(ErrorMessage = Constants.ERROR_REQUIRED)]
[Display(Name = "Tagespreis pro Bett")]
public decimal DailyPricePerBed { get; set; }
[Required(ErrorMessage = Constants.ERROR_REQUIRED)]
[Display(Name = "Price Type required")]
public string PriceType { get; set; }
[StringLength(1000, ErrorMessage = Constants.ERROR_MAX_LENGHT)]
[Display(Name = "Sonstiges")]
public string Memo { get; set; }
[Display(Name = "Bezahlt")]
public bool Paid { get; set; }
public List<Guest> Guests { get; set; }
public List<Room> Rooms { get; set; }
public string GuestName { get; set; }
public string TitleBooking { get; set; }
public bool Selected { get; set; }
public int RoomNumber { get; set; }
public RoomType RoomType { get; set; }
public string EncryptedRoomId { get; set; }
public string EncryptedPartnerId { get; set; }
public string? InvoiceType { get; set; }
}
}
public List<Booking> Load(int roomId)
{
var result = _context.Bookings
.Where(item => item.RoomId == roomId)
.Select(item => _mapper.Map<Booking>(item))
.ToList();
//its takes time here to load each guest name, if i remove
//this part
//its works fast but its showing guest ids on calendar, i want
//to show guest name
foreach (var booking in result)
{
if (_context.Guests.Any(o => o.Id == booking.GuestId)) // update
{
booking.GuestName = _guestRepository.GetName(booking.GuestId);
}
}
return result;
}
You code will be slow for two main reasons. Firstly you are selecting a set of Bookings then using Automapper to "Map" these across to copies of Booking entity classes. If Bookings contain navigation property references to other entities and you have Lazy Loading enabled, this is quite likely resulting in a LOT of lazy load hits as Mapper.Map "touches" each navigation property as it's iterating through the Bookings to copy the object graph across. You are then going and iterating over each booking to call to the GuestRepository to get the guest name, and that could also be of varying efficiency. For instance does the repository do something like:
return _context.Guests.Where(g => g.GuestId == guestId).Select(g => g.GuestName).Single();
or does it do something like:
var guest = _context.Guests.Single(g => g.GuestId == guestId);
return guest.GuestName;
The first runs an SQL Statement to retrieve one column for one row. The second reads all columns from Guest and builds a Guest entity for one row, just to return one value.
The first thing would be to ensure that you have navigation properties defined for all relationships, such as between Bookings and Guests.
From your example I'm guessing this code is part of a BookingRepository which has a dependency on a GuestRepository to get guest information. If there is one piece of advice I can give, it is to avoid the Generic Repository pattern in EF, or thinking of Repositories as serving individual entities. Instead, design Repositories to serve business needs, like a Controller in MVC. If I have a BookingController set up to serve everything to do with making/reviewing bookings, then I can have a BookingRepository to handle all Domain interactions for that Controller. Not just Booking entities, but everything needed for making/reviewing bookings.
The next thing is handling projection. Returning entities outside of the scope of a DbContext that reads them is generally not a great idea. Entities represent data domain. Views have their own concerns with regards to what data they need, and how they want to present it. They should have a purpose-built representation of the domain they are concerned with, a View Model.
So for instance if we have a Booking entity, it should be associated with a Room and a Guest. Each of these would be entities for their respective tables and linked by FKs within the Booking table. What the view is concerned with isn't everything in the Booking, Room, and Guest, just bits of details which can be flattened down from the respective tables and columns. For instance:
public class BookingViewModel
{
public int BookingId { get; set; }
public int RoomId { get; set; }
public int GuestId { get; set; }
public string RoomNumber { get; set;}
public string GuestName { get; set; }
}
Now when we fetch bookings for a given room, without diving into Repositories yet, just working with a DbContext and it's entities:
var bookings = _context.Bookings
.Where(b => b.RoomId == roomId)
.Select(b => new BookingViewModel
{
BookingId = b.BookingId,
RoomId = b.Room.RoomId,
GuestId = b.Guest.GuestId,
RoomNumber = b.Room.RoomNumber,
GuestName = b.Guest.LastName + ", " + b.Guest.FirstName
}).ToList();
With Automapper, we can configure mapping rules for translating a Booking and it's related structure into this BookingViewModel and the above can be simplified to something looking like:
var bookings = _context.Bookings
.Where(b => b.RoomId == roomId)
.ProjectTo<BookingViewModel>(mapperConfig)
.ToList();
Where "mapperConfig" is an instance of a MapperConfiguration set up with the rules to translate Booking -> BookingViewModel. This could be one global Config, or a config built as requested by a factory method.
The benefits with either Select or ProjectTo is that the projection goes directly to the SQL Query so the only data returned is what is needed to populate the view model. There are no risks of lazy loading surprises, or even worrying about tracked entities bogging down the DbContext.
When starting out I would get the hang of using the DbContext and projection without introducing a Repository pattern. The EF DbContext acts as both a Unit of Work and Repository in the sense, and trying to abstract that fact from your application can mean introducing significant performance and flexibility penalties.
For introducing repositories I would recommend either a Repository pattern and Unit of Work pattern that leverage IQueryable so that callers can project details as they need, or having repositories that abstract the domain (entities) into the needs of the consumer. (view models) IQueryable provides a lot of flexibility making Repositories easy to mock for testing, but are coupled to Entity Framework as consumers need to know that fact and manage the DbContext's Scope to use them effectively. Designing repositories that return ViewModels creates a cleaner boundary to isolate consumers from EF, but requires the Repository to have a larger footprint to accommodate all methods, variants, and concerns for the consumer(s). For instance supporting sorting, pagination, etc. Structuring Repositories to serve individual controllers can certainly help compared to repositories-per-entity that serve many controllers with different concerns.
Edit: If updating the result to a view model represents too big of a change, do keep these details in mind for future work because the approach your code base is using is highly inefficient. You Can mitigate the problem to a degree with some smaller changes including loading the entities detached and using Include to Eager-load the required relationships.
The first change would be moving the GuestName into a domain concern that the entity can resolve. Inside the Booking entity change:
public string GuestName { get; set; }
to:
private string _guestName = null;
public string GuestName
{
get
{
return _guestName ?? (_guestName = Guests.SingleOrDefault(g => g.GuestId == GuestId)?.Name;
}
set { _guestName = value; }
}
If you are using .Net Core 6 or 7 this can be simplified to:
private string? _guestName = null;
public string? GuestName
{
get => _guestName ??= Guests.SingleOrDefault(item => item.GuestId == GuestId)?.Name;
set => _guestName = value;
}
Rather than going to the repository for every guest record to get the name, let the entity go to its Guests collection. (if available) This is written as to not break existing code, so any code that "Sets" the guest name will still take precedence.
Alternatively you could use the setter like you are and just go to booking.Guests to get the applicable guest's name rather than going to the repository:
foreach (var booking in result)
{
booking.GuestName = booking.Guests.FirstOrDefault(item => item.GuestId == booking.GuestId)?.Name;
}
If the guest name needs to be formatted from a Guest First and Last Name:
foreach (var booking in result)
{
var mainGuest = booking.Guests.FirstOrDefault(item => item.GuestId == booking.GuestId);
if (mainGuest == null) continue;
booking.GuestName = $"{mainGuest.LastName}, {mainGuest.FirstName}";
}
For methods like this to work, whether using the property or getting the guest from the Guests collection and using the Setter, the entity must have the Guests collection eager loaded, which is the next step:
Eager load any required details your view is going to need about the guest, and detach them:
var result = _context.Bookings
.Include(item => item.Guests)
.Where(item => item.RoomId == roomId)
.AsNoTracking()
.ToList();
This will do something similar to your original code, but it will eager load the Bookings collection, and it will detach the resulting entities so that they won't be lazy-loadable proxies or have changes tracked by the DbContext. The issue with using Mapper.Map without AsNoTracking is that if your DbContext is set up to use lazy loading, the Mapper.Map call will go through each property, which when it hits a navigation property, trigger a lazy load. This will ensure that all data is mapped, but it is extremely slow and inefficient. The above example eager loads the Bookings collection. If there are other navigation properties your view will touch, these will very likely currently be #null now, so you will need to ensure they are eager loaded using Include as well.
Eager loading with Include does come with some performance issues when dealing with one-to-many relationships, especially eager loading several one-to-many relationships in that it produces Cartesian Products where the total volume of data grows by factors with the more relationships you load. This will typically be faster than lazy loading, but still represents a significant resource and performance cost. This is why projecting to a view model is recommended. You will still generate a Cartesian Product, but across far fewer fields as the projection only selects the fields you actually need rather than everything in the associated table. If you are using Eager Loading, eager load only what you know you will need, not everything, or you will soon be facing similar performance and memory bloat problems.
As comments have pointed out, you have not specified which of the parts of that function is consuming the time, nor is it clear what your model looks like.
However, I shall make two assumptions:
the problem is that you are looping through result and then hitting the database for each booking, perhaps twice.
the Guest name property is in the Guests entity / table.
If so, something like the following should speed it up by minimising the database calls to two for the whole function.
// Database Call 1
var result = _context.Bookings
.Where(item => item.RoomId == roomId)
.Select(item => _mapper.Map<Booking>(item))
.ToList();
// Get the Guest Ids used in the booking retrieved above
List<int> guestIds = result.Select(b => b.GuestId).Distinct().ToList();
// Get all Guests that are used - Database Call 2
List<Guest> guests = _context.Guests.Where(g => guestIds.Contains(g.Id)).ToList();
// Now put the name on the bookings
foreach (var booking in result)
{
Guest? guest = guests.SingleOrDefault(g => g.Id == booking.GuestId);
if (guest is not null)
{
booking.GuestName = guest.Name;
}
}
Alternatively, if you have a navigation property to guest from booking, then you can retrieve the guest along with the booking in a single database call like so:
var result = _context.Bookings
.Include(b => b.Guest)
.Where(b => b.RoomId == roomId)
... etc.

One big fat DTO vs multiple skinny DTO [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I'm always struggling with naming convention and design pattern for my application, it's been very hard to keep it consistent, so I have a simple case, let's say I have a service with method called CreateOrder
public OrderDTO CreateOrder(int customerID, OrderShipDTO shipping, OrderDetailDTO products);
Here's the DTO class
public class OrderDTO
{
public int ID { get; set; }
public decimal PriceTotal { get; set; }
public string Status { get; set; }
public string PaymentMethod { get; set; }
public OrderShipDTO OrderShip { get; set; }
public ICollection<OrderDetailDTO> OrderDetails { get; set; }
}
public class OrderShipDTO
{
public string Name { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
public string Province { get; set; }
public string City { get; set; }
public string District { get; set; }
public string SubDistrict { get; set; }
public string ZipCode { get; set; }
}
public class OrderDetailDTO
{
public int ID { get; set; }
public decimal Quantity { get; set; }
public decimal Price { get; set; }
public int ProductID { get; set; }
}
As you can see, my method CreateOrder will return OrderDTO and accept OrderDetailDTO parameters, but the method actually only requires property OrderDetailDTO.ProductID and OrderDetailDTO.Quantity for the business logic calculation.
So, it feels not right for me (and confusing because I wasn't sure which properties need to have a value and which doesn't) to pass the entire OrderDetailDTO object even though it only needs 2 of the properties to be filled, but I still need to pass back the OrderDTO which will include ICollection<OrderDetailDTO> because I need to get the OrderDetailDTO.Price value and show it to my customer.
So I was thinking of creating another DTO like this
public class OrderDetailDTO_2 //temp name
{
public decimal Quantity { get; set; }
public int ProductID { get; set; }
}
But I will end up with a lot of DTOs and even though I'm fine with it, what's the best practice for the DTO naming?
I don't see the point (from the posted info) in having an ID and a ProductId in an orderdetail because the ProductId should be sufficient; if the user adds 2 apples and then adds 3 apples, you can just set the order quantity to 5 apples for the single apples line, rather than distinctly track 2 apples vs 3 apples lines
I don't see the point in not having the price in the orderdetail; items always have a price. It might change or not, but there's no harm in communicating the price to the front end with every back and forth- the front end doesn't have to remember anything then, leading to my next point:
I also don't see the point in having the total in the order unless it is somehow ever going to be different to the sum of all the detail quantity * price. The client can do sums just like the server can. If the client knows the quantity and price, have it work out the total itself
I don't think OrderShip is well named. OrderShip is actually an Address, and looks like it could have plenty of uses in other parts of the program like a billing address, invoicing address, correspondence address. Name your objects according to what they are rather than what they are for - use the name of the variable to indicate what it is for:
public AddressDto ShippingAddress ...
public AddressDto BillingAddress ...
I was thinking of creating another DTO like this
Do not ever create a class name and just whack a 2 on it "because you couldn't think of a better name" - it is absolutely zero help in letting another developer (or yourself by the time you've forgotten this project) know the difference. Hands up anyone who can tell me every difference between an oracle sql VARCHAR and VARCHAR2 without hitting the manual (Gordon, this one's for everyone else ;) )
the method actually only requires property OrderDetailDTO.ProductID and OrderDetailDTO.Quantity for the business logic calculation.
You didn't post any code but there is a reasonable point in the comments that classes can inherit; the base class can have the common properties all classes have, the subclass can have more properties, plus it gets the base ones. The client could send a base class "I want to order apples, 3" and get a subclass "order item apples, 3, $1"
I'm not sure that these arguments warrant creating a whole new class just to dispense with 1 property though. I'd just reuse the same class and sometimes its price is filled in (server to client) and sometimes not/doesn't have to be/ignored (client to server, don't want client setting the prices!)
so I have a simple case, let's say I have a service with method called CreateOrder
Creating an order isn't what I'd call a simple case; it wouldn't need an SO question if it were - your create order method doesn't seem to ask for any payment related argument but the order dto tracks it, so I'm wondering if that is missed off? It's also something I would expect to be done at the end unless you're perhaps allowing the customer to build multiple baskets gradually, and the orderid is generated at the start as a basket reference (in which case perhaps there is a separate process for adding payment info)
At the end of all this, you perhaps need to sit down and map out your workflows first and what data they will need and aim to strike a balance between reusing one mega dto that tracks everything vs having a dto for every case and ending up with 1000 DTOs. These are the two extremes and you will almost never go there. There is always some element of reuse that can and should be applied to limit the maintenance headache. Feel free to inherit classes if they have sensible common base elements, but I wouldn't recommend you have a base OrderDto with the order Id and then DTOs for createorder, updateorder, cancelorder, addordershippingaddress, changeordershippingaddress, changeorderbillingaddress, reportorderreceived, reportordernotreceived etc - most of those operations only need an order Id, maybe an address detail or order detail; you can have a couple of dto; the base order (for operations like cancel, report received etc) and the full one (with null billing address if you're changing the shipping address).
You can use the name of the method being called to know whether it's the billing or shipping you need to change, or the client can just send a pair of modified addresses (both addresses need updating), a modified and unmodified address (update one address but not the other), a null and nonnull address (remove one address but not the other) ... and the server can process them all in the same way: the new address pair is the truth; overwrite the old data with the new.
This has struck a balance between the dto extremes; if we happen upon a situation where neither dto applies, then we can consider making another if no existing one is ideal. We shouldn't use fields for things other than which they were intended (don't use the credit card number field to store the phone number if they person pays by bank transfer) even if it is "just that one time" - perhaps adding a phone number would be an opportunity to extend the Address dto and call it something different like ContactDetail
At first you have to know your business logic and the required business entities. Without knowing any details about the application's business, the business logic can always be viewed as a black box, which requires input, processes this input and produces output i.e. a result (IPO model).
With the IPO model in mind, you can now design your business entities around the business logic. Identify the business process, derive the logic and design the required entities (their behavior or attributes and relationships). Start to design interfaces to describe those entities.
Note that it is not the goal to have a dedicated object for each method, so that each object only exposes the data the method needs. Although interface segregation is a good approach to achieve this, by encapsulating data contexts or responsibilities.
Since you have expressed your focused on naming conventions, also note that there is no value in adding a prefix or suffix to the type name that describes their physical (e.g. bool) or logical (e.g., DTO) data type. There is absolutely no value in this naming style. It only makes the names ugly and degrades readability. This is the main reason why e.g., Hungarian Notation is obsolete today.
Example
I assume that your business logic's goal is to create an actual order based on the data input provided by a user. This example of course is based on a very simplified process.
You can always use interface segregation to encapsulate responsibilities. An object that implements fine grained interfaces, can be passed around by this interfaces, allowing fine grained context related exposition of attributes.
Data input business entities
interface IItem
{
decimal Quantity { get; set; }
int ProductID { get; set; }
}
// Describes data needed for shipping related to a customer
interface IShippingAddress
{
string Address { get; set; }
string Province { get; set; }
string City { get; set; }
string District { get; set; }
string SubDistrict { get; set; }
string ZipCode { get; set; }
}
// Consolidates data needed to create an order.
// Provided by customer order process.
interface IPurchase
{
int CustomerId { get; set; }
IShippingAddress ShippingAddress { get; set; }
IEnumerable<IItem> Items { get; set; }
}
Data output business entities
// Result entity that extends IITem to add internal details like price.
interface IOrderItem : IItem
{
int Id { get; set; }
decimal Price { get; set; }
}
// Encapsulates contact details
interface ICustomerContactInfo
{
string Phone { get; set; }
string EmailAddress { get; set; }
}
// Encapsulates customer details like IsVip, or contact info etc
interface ICustomerInfo : ICustomerContactInfo
{
int CustomerId { get; set; }
string Name { get; set; }
}
// Consolidates the data needed for the shipping process
interface IShippingInfo : ICustomerInfo, IShippingAddress
{
}
// Consolidates and adds data needed for managing the order's delivery process
interface IDelivery : IShippingInfo
{
bool IsInDelivery { get; set; }
DateTime PickupDate { get; set; }
DateTime DueDate { get; set; }
}
// The result entity
interface IOrder
{
int Id { get; set; }
decimal PriceTotal { get; set; }
string Status { get; set; }
string PaymentMethod { get; set; }
IDelivery DeliveryInfo { get; set; }
ICollection<IOrderItem> Items { get; set; }
}
Business logic
public IOrder CreateOrder(IPurchase purchase)
{
// Get the result item info that contains actual price etc
ICollection<IOrderItem> orderItems = GetOrderItems(purchase.Items);
ICustomerInfo customer = GetCustomer(purchase.CustomerId);
IShippingInfo shippingInfo = CreateShippingInfo(purchase.ShippingAddress, customer);
IOrder result = CreateOrderItem(orderItems, shippingInfo);
return result;
}
public void SendConfimationMail(ICustomerContactInfo contactInfo)
{
SendMailTo(contactInfo.EmailAddress, message);
}
public void OrderDeliveryService(IShippingInfo shippingInfo)
{
SubmitDeliveryOrder(shippingInfo);
}
Example
public static Main()
{
IPurchase purchase = CollectOrderDataFromUser();
IOrder orderItem = CreateOrder(purchase);
// Only pass the ICustomerContactInfo part of IDelivery as argument
SendConfimationMail(orderItem.DeliveryInfo);
// Only pass the IShippingInfo part of IDelivery as argument
OrderDeliveryService(orderItem.DeliveryInfo);
}
The degree of segregation or the design of the interfaces may not make much sense for you. But the goal of this example is to provide a raw and basic example on how to design business entities, that reflect the business logic, which reflects the real life business process. It shows how interface segregation helps to pass around only a specific context (interface) of an object to enforce encapsulation or to limit greediness.

How to identify a dependent entity in one to one relationship Entity Framework Core?

I have studied many articles about how to config one to one relationships. I have learned it.
But I couldn't understand how to find a dependent entity in one to one relationship?
For instance, we have two entities User and Developer. How to understand which of them is a dependent entity? Because I think we must add a foreign key to a dependent entity. So the first things to do, we need to find a dependent entity.
public class User
{
public int Id {get;set;}
public string PasswordHash { get; set; }
public string FullName { get { return FirstName + " " +LastName;}}
public GenderType Gender { get; set; }
public bool IsActive { get; set; }
public DateTimeOffset LastLoginDate { get; set; }
public string FirstName { get ; set ; }
public string LastName { get; set; }
}
public class Developer
{
public int Id { get; set; }
public byte Image { get; set; }
public int Age { get; set; }
public string Resume { get; set; }
}
A dependent is something that depends on something else. A baby is dependent on its mother for food etc. Identify which entity can stand alone, without the other.
For example, you may decide that a User might not be a Developer but a Developer is always a User - in this case your relationship is actually 1:0..1 (user:developer) and you're looking at Developer being a subclass of a User. If. You could alternatively arrange things in a has-a fashion, and Developer has a User property (but User doesn't have a Developer property because not every User is a developer)
You may decide that you can never have one without the other- in which case they would probably be a good candidate for being in the same table/same client side entity
To some extent the question can be academic; there may be situations where you want to treat one as dependent, and others where it's the inverse way round. It'll probably help you overall though if you make a decision about how your entities are related on the client side and this will drive how you map them on the database side

Web Api, Update DB, connection reset 200ok

I have asp.net web api application. I have the table Companies in the databse which have two fields: id and description. Recently I've updated the database and added a new column called CustomerID. After that when I am trying to call getCompanies
private readonly BackendContext _context;
public CompaniesController(BackendContext context)
{
_context = context;
}
// GET: api/Companies
[HttpGet]
public IEnumerable<Company> GetCompanies()
{
return _context.Companies;
}
I get
I think the controller tries to return the old companies model but can't achieve it because it doesnt exist now but I don't know how to fix this though the controller should return the updated model. Maybe I should somehow rebuild the app to make it use the updated version?
Additional code:
Context
public class BackendContext : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext<IdentityUser>//DbContext
{
public BackendContext(DbContextOptions<BackendContext> options) : base(options) { }
public DbSet<Company> Companies { get; set; }
public DbSet<CompanyToProduct> CompanyToProducts { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Vendor> Vendors { get; set; }
public DbSet<VendorToProduct> VendorToProducts { get; set; }
public DbSet<Invoice> Invoices { get; set; }
public DbSet<InvoiceItem> InvoiceItems { get; set; }
}
Model
public class Company
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<CompanyToProduct> CompaniesToProducts { get; set; }
public virtual ICollection<Invoice> Invoices { get; set; }
}
UPDATE
I've added some values to the table and I got the response of the first company:
[{"id":1,"name":"Google","description":"free food","customerID":6,"customer":null,"companiesToProducts":null,"invoices":null}
BUT I also got the fields which is not specified in the table: customer, companiesToProducts,invoices. Invoices and companiesToProducts are tables in my database and I don't know what is customer referred to. I should also mention that these tables are connected by foreign key.
UPDATE
Error:
Based on the comments on the question above, it sounds like the related tables are all trying to serialize and the overall process is failing likely due to circular references in the object graph. This comment above in particular hints at a solution:
I want to return only the data about companies but the controller also returns another fields like customer, companiesToProducts,invoices
While it's convenient to just return directly from the data context, this has the added side-effect of coupling the API with the database (and with the data access framework, which appears to be the issue here). In API design in general it's always a good idea to explicitly define the "shape" of that API. The fields to return, etc.
Project your result into an explicitly defined shape and return only what you want to return:
var result = _context.Companies
.Select(c => new
{
c.ID,
c.Name,
c.Description,
c.CustomerID
})
.ToList();
This defines specifically what you want to return, fetches only that information from the backing data, materializes it into an in-memory list, and finally then returns it through the API.
There is a potential downside to this, however. Because now we also need to change the return type of your API method. There are a couple options there, such as returning a generic response object or creating a view model which closely approximates your already existing model and starts to feel like duplication.
As with just about anything, it's a balance. Too far in any one direction and that direction starts to become a problem. Personally I often go the route of defining a view model to return:
public class CompanyViewModel
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CustomerID { get; set; }
}
and returning that:
return _context.Companies
.Select(c => new CompanyViewModel
{
ID = c.ID,
Name = c.Name,
Description = c.Description,
CustomID = c.CustomerID
})
.ToList();
But the reason I normally do this is because I normally work in an environment where the web application is just one application attached to a common shared business domain, so the view models don't feel like code duplication. They're in a separate project, often take a different shape than the backing data objects, etc. But if your domain models are already in your web project and that's the only project you have, there's a strong desire to want to return those.
Another option when that's the case could be to universally set your JSON serialization to ignore circular references:
services.AddMvc()
.AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore );
But do keep in mind that this still couples your API to your DB models. Maybe that's okay in this project, but if you ever add a column to your DB that you don't want users to see then it becomes an issue. As with anything, you have options.

How can I cache a has-many relationship with entity 6 framework?

I have an application that is written on the top of ASP.NET MVC5 framework along side with Entity 6 Framework.
Typically, caching relations does isn't helpful. However, I have a case where the related data never change, but the parent does. I am looking for a way to cache the relations only so I don't have to make hard read each time the page is loaded.
I have the following two classes
public class Item
{
public string Id { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public decimal Rate { get; set; }
...
...
public virtual ICollection<ItemRecord> Records { get; set; }
}
public class ItemRecord
{
public string Id { get; set; }
public string Title { get; set; }
public decimal Description { get; set; }
public decimal Amount { get; set; }
[ForeignKey("Item")]
public int ItemId { get; set; }
...
...
public virtual ItemRecord Item { get; set; }
}
Within my Index action in the controller, I can get the data using the following linq statement.
public ActionResult Index(int? id)
{
if(id.HasValue)
{
var items = Context.Items.Where(item => item.CategoryId == id.Value)
.Include(x => x.Records)
.ToList();
}
....
}
Since the Item model changes all the time, I don't want to cache it. However, I want to cache all the data in Records relation since it never changes and it is large data set.
Question
How can I cache the Records relation in my above example?
I tried to use OutputCache attribute to cache the relation like so
public class Item
{
public string Id { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public decimal Rate { get; set; }
...
...
[OutputCache(Duration = 3600, VaryByParam = "CategoryId", Location = OutputCacheLocation.Server)]
public virtual ICollection<ItemRecord> Records { get; set; }
}
as you can tell that did not work, this is the error I got
Attribute 'OutputCache' is not valid on this declaration type. It is
only valid on 'class, method' declarations.
Apparently OutputCache is for caching classes not entity relations.
No, OutputCache is for caching the response of an action. It literally caches the whole response so the action itself does not have to be run. It is not appropriate for scenarios where you just want to cache particular data.
For that, you need something like MemoryCache or a NoSQL solution like Redis. MemoryCache is generally easier to use, but has important limitations:
As its name implies, the cache is in-memory, and therefore only survives as long as the memory is reserved. Namely, restarting the server, or simply having the AppPool stop, either as part of normal recycling, explicit shutdown, or crashing, will wipe everything you've cached. It will also be effected by normal memory optimization. If for example, the OS needs to reclaim memory for another process, the cache will be one of the first things to be sacrificed.
It's process-bound, if you're utilizing multiple processes (web garden), the cache will be unique per process, which could mean including the same data in memory multiple times, once for each process.
If you want a more stable cache, you'd need to use something like Redis, which while also an in-memory system, is backed by the filesystem and can also be distributed. That means you can have it running on a totally different server or even multiple different servers for failover redundancy. This will be a little more difficult to implement, as you have to actually set up Redis and configure the connection to it, but I specifically recommend Redis, here, because Microsoft has done a lot of work already to ensure it plays well both with Windows and with things like ASP.NET applications. Redis is actually the backing behind Azure Cache, so they're motivated both to make it seamless and keep on top of updates and such.

Categories

Resources