Hi I'm new with Entity Framework, this is what i need, have two classes, let's say "Customer" and "Orders":
Class CustomerBE<br/>
{
Public int CustomerID { get;set;}
...Other properties<br/>
}
Class OrderBE<br/>
{
Public int OrderID{ get; set; }
Public int CustomerID{ get;set;}
Public CustomerBE Customer {get;set}
}
How to mapping the order to customer ?, i have read some others posts and some others examples, what they are doing is to create a icollection of orders in customerBE, something like:
Class CustomerBE
{
Public int CustomerID{get;set;}
Public Virtual ICollection Orders<orderBE>{get;set;}
}
And then they map the customer to have many orders, using the orders collection in the customer class, but, for me that is incorrect, the consumer of the class, will be able to use the orders property on the customer class to access all the orders from the customer, and i don't what to let them do that:
ICollection<OrderBE> customerOrders = customer.Orders //I don't what this
In what scenario i would like to get all the customer orders?, usually we wan't the customer orders by a given criteria (date, status, etc.), so instead of use that property, for me, i think it's better to use the orders repository to access the customer orders by a given criteria, something like:
ICollection customerOrders = ordersRepository.GetCustomerOrdersByDate(customer.ID, Today.Date) //This is what i want, not orders = customer.oders
so any body knows how to do the mappings between order and customer using code first approach without have an orders collection in the customer class ?
Use the Fluent API in your DbContext class:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<OrderBE>().HasRequired(x => x.Customer);
}
Related
I have been reading that Repositories should return domain objects only. I am having difficulty with implementing this. I currently have API with Service Layer, Repository and I am using EF Core to access sql database.
If we consider User(Id, Name, address, PhoneNumber, Email, Username) and Orders (id, OrderDetails, UserId) as 2 domain objects. One Customer can have multiple Orders. I have created navigation property
public virtual User User{ get; set; }
and foreign Key.
Service layer needs to return DTO with OrderId, OrderDetails, CustomerId, CustomerName. What should the Repository return in this case? This is what i was trying:
public IEnumerable<Orders> GetOrders(int orderId)
{
var result = _context.Orders.Where(or=>or.Id=orderId)
.Include(u => u.User)
.ToList();
return result;
}
I am having trouble with Eager loading. I have tried to use include. I am using Database first. In the case of above, Navigation Properties are always retuned with NULL. The only way i was able to get data in to Navigation Properties was to enable lazy loading with proxies for the context. I think this will be a performance issue
Can anyone help with what i should return and why .Include is not working?
Repositories can return other types of objects, even primitive types like integers if you want to count some number of objects based on a criteria.
This is from the Domain Driven Design book:
They (Repositories) can also return symmary information, such as a
count of how many instances (of Domain Object) meet some criteria.
They can even return summary calculations, such as the total across
all matching objects of some numerical attribute.
If you return somethings that isn't a Domain Objects, it's because you need some information about the Domain Objects, so you should only return immutable objects and primitive data types like integers.
If you make a query to get and objects with the intention of changing it after you get it, it should be a Domain Object.
If you need to do it place boundaries around your Domain Objects and organize them in Aggregates.
Here's a good article that explains how to decompose your model into aggregates: https://dddcommunity.org/library/vernon_2011/
In your case you can either compose the User and the Order entities in a single Aggreate or have them in separate Aggregates.
EDIT:
Example:
Here we will use Reference By Id and all Entities from different Aggregates will reference other entities from different Aggregates by Id.
We will have three Aggregates: User, Product and Order with one ValueObject OrderLineItem.
public class User {
public Guid Id{ get; private set; }
public string FirstName { get; private set; }
public string LastName { get; private set; }
}
public class Product {
public Guid Id { get; private set; }
public string Name { get; private set; }
public Money Price { get; private set; }
}
public class OrderLineItem {
public Guid ProductId { get; private set; }
public Quantity Quantity { get; private set; }
// Copy the current price of the product here so future changes don't affect old orders
public Money Price { get; private set; }
}
public class Order {
public Guid Id { get; private set; }
public IEnumerable<OrderLineItem> LineItems { get; private set; }
}
Now if you do have to do heavy querying in your app you can create a ReadModel that will be created from the model above
public class OrderLineItemWithProductDetails {
public Guid ProductId { get; private set; }
public string ProductName { get; private set; }
// other stuff quantity, price etc.
}
public class OrderWithUserDetails {
public Guid Id { get; private set; }
public string UserFirstName { get; private set; }
public string UserLastName { get; private set; }
public IEnumerable<OrderLineItemWithProductDetails > LineItems { get; private set; }
// other stuff you will need
}
How you fill the ReadModel is a whole topic, so I can't cover all of it, but here are some pointers.
You said you will do a Join, so you're probably using RDBMS of some kind like PosteSQL or MySQL. You can do the Join in a special ReadModel Repository. If your data is in a single Database, you can just use a ReadModel Repository.
// SQL Repository, No ORM here
public class OrderReadModelRepository {
public OrderWithUserDetails FindForUser(Guid userId) {
// this is suppose to be an example, my SQL is a bit rusty so...
string sql = #"SELECT * FROM orders AS o
JOIN orderlineitems AS l
JOIN users AS u ON o.UserId = u.Id
JOIN products AS p ON p.id = l.ProductId
WHERE u.Id = userId";
var resultSet = DB.Execute(sql);
return CreateOrderWithDetailsFromResultSet(resultSet);
}
}
// ORM based repository
public class OrderReadModelRepository {
public IEnumerable<OrderWithUserDetails> FindForUser(Guid userId) {
return ctx.Orders.Where(o => o.UserId == userId)
.Include("OrderLineItems")
.Include("Products")
.ToList();
}
}
If it's not, well you will have to build it an keep it in a separate database. You can use DomainEvents to do that, but I wont go that far if you have a single SQL database.
The advice I give around the repository pattern is that repositories should return IQueryable<TEntity>, Not IEnumerable<TEntity>.
The purpose of a repository is to:
Make code easier to test.
Centralize common business rules.
The purpose of a repository should not be to:
Abstract EF away from your project.
Hide knowledge of your domain. (Entities)
If you're introducing a repository to hide the fact that the solution is depending on EF or hide the domain then you are sacrificing much of what EF can bring to the table for managing the interaction with your data or you are introducing a lot of unnecessary complexity into your solution to try and keep that capability. (filtering, sorting, paginating, selective eager loading, etc.)
Instead, by leveraging IQueryable and treating EF as a first-class citizen to your domain you can leverage EF to produce flexible and fast queries to get the data you need.
Given a Service where you want to " return DTO with OrderId, OrderDetails, CustomerId, CustomerName."
Step 1: Raw example, no repository...
Service code:
public OrderDto GetOrderById(int orderId)
{
using (var context = new AppDbContext())
{
var order = context.Orders
.Select(x => new OrderDto
{
OrderId = x.OrderId,
OrderDetails = x.OrderDetails,
CustomerId = x.Customer.CustomerId,
CustomerName = x.Customer.Name
}).Single(x => x.OrderId == orderId);
return order;
}
}
This code can work perfectly fine, but it is coupled to the DbContext so it is hard to unit test. We may have additional business logic to consider that will need to apply to pretty much all queries such as if Orders have an "IsActive" state (soft delete) or the database serves multiple clients (multi-tenant). There will be a lot of queries in our controllers and would lead to the need for a lot of things like .Where(x => x.IsActive) included everywhere.
With the Repository pattern (IQueryable), unit of work:
public OrderDto GetOrderById(int orderId)
{
using (var context = ContextScopeFactory.CreateReadOnly())
{
var order = OrderRepository.GetOrders()
.Select(x => new OrderDto
{
OrderId = x.OrderId,
OrderDetails = x.OrderDetails,
CustomerId = x.Customer.CustomerId,
CustomerName = x.Customer.Name
}).Single(x => x.OrderId == orderId);
return order;
}
}
Now at face value in the controller code above, this doesn't really look much different to the first raw example, but there are a few bits that make this testable and can help manage things like common criteria.
The repository code:
public class OrderRepository : IOrderRepository
{
private readonly IAmbientContextScopeLocator _contextScopeLocator = null;
public OrderRepository(IAmbientContextScopeLocator contextScopeLocator)
{
_contextScopeLocator = contextScopeLocator ?? throw new ArgumentNullException("contextScopeLocator");
}
private AppDbContext Context => return _contextScopeLocator.Get<AppDbContext>();
IQueryable<Order> IOrderRepository.GetOrders()
{
return Context.Orders.Where(x => x.IsActive);
}
}
This example uses Mehdime's DbContextScope for the unit of work, but can be adapted to others or an injected DbContext as long as it is lifetime scoped to the request. It also demonstrates a case with a very common filter criteria ("IsActive") that we might want to centralize across all queries.
In the above example we use a repository to return the orders as an IQueryable. The repository method is fully mock-able where the DbContextScopeFactory.CreateReadOnly call can be stubbed out, and the repository call can be mocked to return whatever data you want using a List<Order>().AsQueryable() for example. By returning IQueryable the calling code has full control over how the data will be consumed. Note that there is no need to worry about eager-loading the customer/user data. The query will not be executed until you perform the Single (or ToList etc.) call which results in very efficient queries. The repository class itself is kept very simple as there is no complexity about telling it what records and related data to include. We can adjust our query to add sorting, pagination, (Skip/Take) or get a Count or simply check if any data exists (Any) without adding functions etc. to the repository or having the overhead of loading the data just to do a simple check.
The most common objections I hear to having repositories return IQueryable are:
"It leaks. The callers need to know about EF and the entity structure." Yes, the callers need to know about EF limitations and the entity structure. However, many alternative approaches such as injecting expression trees for managing filtering, sorting, and eager loading require the same knowledge of the limitations of EF and the entity structure. For instance, injecting an expression to perform filtering still cannot include details that EF cannot execute. Completely abstracting away EF will result in a lot of similar but crippled methods in the repository and/or giving up a lot of the performance and capability that EF brings. If you adopt EF into your project it works a lot better when it is trusted as a first-class citizen within the project.
"As a maintainer of the domain layer, I can optimize code when the repositories are responsible for the criteria." I put this down to premature optimization. The repositories can enforce core-level filtering such as active state or tenancy, leaving the desired querying and retrieval up to the implementing code. It's true that you cannot predict or control how these resulting queries will look against your data source, but query optimization is something that is best done when considering real-world data use. The queries that EF generates reflect the data that is needed which can be further refined and the basis for what indexes will be most effective. The alternative is trying to predict what queries will be used and giving those limited selections to the services to consume with the intention of them requesting further refined "flavours". This often reverts to services running less efficient queries more often to get their data when it's more trouble to introduce new queries into the repositories.
Suppose I have Employee class, should I put in the Employee class the add, delete, view, etc. methods? or should that class only for the getter/setter class?
which is better/acceptable/best practice?
Employee
-------------------
+int id (get/set)
+string name (get/set) (methods are called in another class)
Employee
-------------------
+int id (get/set)
+string name (get/set)
-add employee
-remove employee
This comes down to separation of concerns
When you are deciding these things, you need to use your intuition and think about it logically. What concerns an employee.
You have a class called Employee, then include in the Employee class everything that concerns an Employee. It doesn't make sense for an employee to be able to Add and Remove Employees to themselves. Maybe what you are looking for there is a class of Employees (plural) that will manage your employees ect ect ect.
But your Employee "will" have Name and Id and other things that concern it.
The goal here is to break up your concepts in to concrete real world concerns as much as possible, it makes it much easier to understand a design if you do
Assuming you have a database behind:
For similar purposes I have a base class for all entities that takes care of CRUD functionality and the ID. All entities inherit from this base class and take care of individual properties, like name, address, etc.
Also I have collections of all entities of the same type that manage the items in it.
Short Answer: Go with option 2
If you consider the separations of concerns, you should have an Employee to track the information of a single person and an Employee Repository for managing all of your employees. What makes up an record should be independent from how the record is stored/queried.
Employee class has information of employee, and the methods of employee. Looks like you are trying to maintain a collection of employees (assuming from add, delete employee requirement)
In that case add,delete,remove are not the responsibilities of employee class, rather the collection of employees.
Read on the OOP principles.
First 5 Principles of Object Oriented Design(S.O.L.I.D).
After Employee
public class Employee :ViewModelBase, IEditableObject
{
public int EmployeeID { get; set; }
public string FullName
{
get
{
return $"{this.Name} {this.Surname}";
}
}
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
OnPropertyChanged("Name");
}
}
}
After Create a Generics class with Repository For managment Add,Delete,Update etc...
public interface IRepository<T> where TEntity : class
{
IEnumerable<TEntity> GetUsers();
IQueryable<TEntity> SearchFor(Expression<Func<TEntity, bool>> predicate);
TEntity GetById(int id);
void Save(TEntity model);
void Delete(int id);
}
And Employee Base implementation Repository
public Class EmployeeManager : Repository<Employee>
{
public IEnumerable<TEntity> GetUsers()
{
//your code
}
public IQueryable<TEntity> SearchFor(Expression<Func<TEntity, bool>> predicate)
{
//your code
}
public TEntity GetById(int id)
{
//your code
}
public void Save(TEntity model)
{
//your code
}
public void Delete(int id)
{
//your code
}
public void DeleteAll(Employee[] employees)
{
//your code
}
}
Unity Repository Best Practices
I think you should have all the tools you need in one class, have multiple constructors to help load only the info as needed.
I want to create a specific class to manage a collegion in my application.
For example, I have a Store and I have a list of customers in a collection, in this collection I have a customer that is the customer of the month, and some customers that got a prize to get a discount for some reason. Let's get to the code:
public class Store {
public ICollection<Customer> Customers { get; set; }
public Customer CustomerOfTheMonth
{
//get and set for customer of the month
}
public ICollection<Customer> DiscountCustomers
{
//get and set for customer of the month
}
public ICollection<Customer> GetAllCustomers
{
//get and set for customer of the month
}
}
But in my database, I only have two tables. Store, and Customer.
What I want to do is create a specific collection for the customer, to remove the logic from the Store and put in a specific class, after all, I don't feel that the logic belongs to neither of those classes.
I wans tomething like this:
public class Store {
internal CustomerCollection Customers { get; set; }
//get and set for the propertis, just delegating for the collection
}
public class CustomerCollection {
public ICollection<Customer> Customers { get; set; }
public ICollection<Customer> DiscountCustomers
{
//get and set for customer of the month
}
//get and set with logic to filter the collection
}
Is there away to create this mapping and keep with only two tables in the database? I want to make it transparent to the application. Sorry for the code problems, typed in stack overflow and didn't check the syntax.
don't need to create your business logic to your model classes. Separate your logic to upper level. Here are your model classes. It will create your relationships as you want
public class Store {
public vertual ICollection<Customer> Customers { get; set; }
//get and set for other propertis
}
public class Customer{
//get and set for other propertis
}
Create a repository or service layer to apply specific business logic ,
public ICollection<Customer> GetDiscountCustomers()
{
return dbContext.Customers.where(c=>c.discount=true).ToList()
}
if you want to load stores with customers at once you can use eager loading,
public ICollection<Store> GetAllStores()
{
return dbContext.Stores.Include("Customers").ToList()
}
The Model as below:
public class User
{
public int Id
public virtual ICollection<Tag> FollowingTags {get;set;}
}
public class Tag
{
public int Id
public virtual ICollection<User> Followers {get;set;}
public virtual ICollection<Post> Posts {get;set;}
}
public class Post {
public int Id
public virtual ICollection<Tag> Tags {get;set;}
}
That means there are two many-to-many from User to Post, perhaps it can be called a M:M:M relationship.
Now, if I want to find all posts with tags that followed by a certain User. I wonder what is the best practice with EF 4.1?
If use ADO.NET, I think joining two joint tables is effective way, but joint tables are hidden in EF, then how to do it ? I know some solutions, but the performance is not good, because the generated SQL not good enough. so I ask for a good query to get good performance.
Thank you!
Try using the "include" modifier in your query like:
context ctx = new context() // context is the entity context in this case
var query = from p in ctx.posts.include("tags.users")
where p.tags.Followers.ID = TargetUserID
This should cover it
(from p in db.Posts
from t in p.Tags
from f in t.Followers
where f.Id == id
select p).Distinct()
Ok, I'm pretty sure its just a matter of learning... but I have a very normalized db i'm working with so when I save to my product tbl I also have a productDollar tble and so on...
my question is in silverlight everything is async so How do I save a product get back its new id and use that as the productDollar.productID fk
so far with my other saves i just use the submitOperation in the callback of the submitchanges
and in there i check for iscompleted and do the next save and so on... and chain them together like that.
but I have 500 products I need to save (all at once)
so doing a foreach around my product object won't work because of the wonderful async
So what am I missing??? any help or pointers would be GREATLY appreciated
WCF RIA Services had this situation in mind when it was created. You can easily do it all in one SubmitChanges request and in one database transaction (depending on your DB and/or ORM). However, if you provide some more information about your objects (POCO, EF, etc.), you'll get a better answer.
That said, I'll take a wild guess at your objects as defined on the server.
public class Product
{
[Key]
public int? ProductID { get; set; }
// ... more properties ...
[Association("Product-ProductDollars", "ProductID", "ProductID", IsForeignKey = false)]
[Include]
[Composition]
public ICollection<ProductDollar> ProductDollars { get; set; }
}
public class ProductDollar
{
[Key]
public int? ProductDollarID { get; set; }
public int? ProductID { get; set; }
// ... more properties ...
[Association("Product-ProductDollars", "ProductID", "ProductID", IsForeignKey = true)]
[Include]
public Product Product { get; set; }
}
And your DomainService looks something like
public class ProductDomainService : DomainService
{
public IQueryable<Product> GetProducts()
{
// Get data from the DB
}
public void InsertProduct(Product product)
{
// Insert the Product into the database
// Depending on how your objects get in the DB, the ProductID will be set
// and later returned to the client
}
public void InsertProductDollar(ProductDollar productDollar)
{
// Insert the ProductDollar in the DB
}
// Leaving out the Update and Delete methods
}
Now, on your client, you'll have code that creates and adds these entities.
var context = new ProductDomainContext();
var product = new Product();
context.Products.Add(product);
product.ProductDollars.Add(new ProductDollar());
product.ProductDollars.Add(new ProductDollar());
context.SubmitChanges();
This results in one request sent to the DomainService. However, WCF RIA splits this ChangeSet containing the 3 inserts into 3 calls to your DomainService methods:
InsertProduct(Product product)
InsertProductDollar(ProductDollar productDollar)
InsertProductDollar(ProductDollar productDollar)
If your DomainService performs all inserts in one transaction, the ProductID can be correctly managed by your ORM.