2

I'm working on a very large non-MVC project utilizing Entity Framework for database access. This is a new project, so we've got a wide-open canvas for development.

The conceptual problem I'm running into is how to model the layer just above the EF Models.

At the database level I've got a Customer, Order, and Item table so there's a model for each.

Now I need to describe what the Customer can do. For example, ultimately I want to say something like:

 Order newOrder = customerObject.CreateOrder(itemList);

Where does the method CreateOrder live?

My gut tells me that there's a sub-class of the Customer Model that has the methods needed by the Customer. With an interface to that class up front to keep the cross-dependencies between modules low.

But this sounds too easy to be the correct way.

Some related questions I've found, but didn't exactly apply are:

1
2

The one that I have used which worked quite nicely. Basically used repositories to house the methods called. Everything was divided into:

  • Context: Sets up your db context using the below, implements System.Data.Entity.DbContext. It contains DbSet's of your entities. So a sample will look like below:

    public DbSet<Customer> Customers { get; set; }
    
    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    {
        Database.SetInitializer<CustomerDatabaseContext>(null);
    
        modelBuilder.Configurations.Add(new CustomerConfiguration()); 
    }
    
  • Entities: Literal mapping of db object

    public class Customer
    {
        public long Id {get; set;}
    
        public string Name {get; set;}
    }
    
  • Configurations: Setting up your entity

    public class CustomerConfiguration : EntityTypeConfiguration<Customer>
    {
        public CustomerConfiguration()
        {
            this.Property(x => x.Id).HasColumnName("CustomerId");
            this.HasKey(x => x.Id);
            this.Property(x => x.Name);
        }
    }
    
  • Repositories: Holds all the methods e.g.

    public Customer GetById(long identity)
    {
        using (var context = CustomerDatabaseContext.Start())
        {
            return context.Customers.FirstOrDefault(x => x.Id == identity);
        }
    }
    
  • The repositories are initialised in code and used e.g.

    var customer = this.repository.GetById(request.CustomerId);
    
4
  • IMHO, repository pattern (atop EF which is already a repository) is redundant. I feel this would be better served as a service (which accepts a repository, or, in this case, the EF context). Sep 1 '15 at 15:11
  • Ah hang on that time we did code first, are you importing the model?
    – nicV
    Sep 1 '15 at 15:18
  • This project is strictly DB first. We've got one of those cases where the DB has to be designed very carefully. The models we're just pulling in from the DB as-is pretty much. Sep 1 '15 at 17:06
  • Hmmm I had a project like that as well, just can't remember as well. Pretty sure we extended the partial repositories? Will give it some thought though.
    – nicV
    Sep 1 '15 at 18:23
1

Everyone appears to be on the repository train. Given EF is already a repository, I would push to house business logic on a service layer. A service doesn't necessarily have to be in a new library (though it could), but does provide that additional logic atop the base entities. To illustrate:

public interface IOrderService : IDisposable
{
    Order Create(Customer customer, params Item[] items);
}

public class OrderService : IOrderService
{
    private DbContext context;

    public OrderService(DbContext context)
    {
        Contract.Requires(context != null);

        this.context = context;
    }

    public Order Create(Customer customer, params Item[] items)
    {
        Contract.Requires(customer != null);
        Contract.Requires(items != null);
        Contract.Requires(items.Length > 0);
        Contract.Ensures(Contract.Result<Order>() != null);

        Order order;

        //
        // Business logic building order;
        //

        return order;
    }
}

Then usage would look something like:

// -- Existing variables --
var db = /* your EF context */;
var customer = /* your targetted customer */;
var items = /* the items to be added */;
// -- /Existing variables --

// Executing against new service
var orderSvc = new OrderService(db);
var newOrder = orderSvc.Create(customer, items);

Commentary

All a repository pattern does (on top of an ORM) is abstract out the API that's already there. Now you're duplicating efforts, and, a lot of the time, losing some very cool features of the ORM itself (this is why you chose the ORM over using SqlConnection I would presume...). Sure, you might change out your ORM months/years from now, but is it worth the up-front effort? (That's for you to decide)

4
  • 1
    "Given EF is already a repository ..." Here is my opinion on how EF is not a Repository. Having said that, I would probably do something much like your answer. :-)
    – Eric King
    Sep 1 '15 at 16:13
  • A service layer would be adequate for us, more abstractions aren't really necessary at this level in this project. We are effectively supplying just a business-layer API. I'll read up on this particular pattern, but it sounds like a good start. Sep 1 '15 at 17:11
  • As a followup, in this pattern what would you do when you needed Order to do something? Maybe to (later) compute the order total or discounts? Would you have to extent the Order class, or would you call the OrderService passing in the order as the first argument? Sep 2 '15 at 17:28
  • IMHO, keep the entities POCOs and apply any kind of logic (like what you've mentioned) in a service. That said, also keep similar logic tied by a single unit of work (Order service should do things related to orders, Customer service may update customer email, etc.). And, yes, passing in the Order is acceptable. Sep 2 '15 at 17:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.