DRY Entity Framework Search Call

混江龙づ霸主 提交于 2019-12-10 19:03:47

问题


I have an Entity Framework (v5.0) DbContext called Entities that is auto-generated by the framework (I think my design pattern is Database First).

I have this search command (shown in the snippet below) that I am calling throughout the application. I want to DRY up my controller code and re-factor this into a method call.

using (var db = new Entities())
{
    DateTime now = DateTime.Today;
    var activeEvents = db.Events.Where(
        b => !b.removed &&
        b.start_date <= now &&
        b.end_date >= now
    );
}

Example after re-factoring.

using (var db = new Entities())
{
    var activeEvents = db.Events.GetActive();
    // Or maybe it looks like db.GetActiveEvents();
    // I assume this is dictated by best practice
}

How would one go about achieving this? What is considered best practice?


回答1:


I would probably take the service approach; You build your site with three main components:

  • Presentation Layer
    This is the MVC website (but could be a mobile site, and application, whatever)
  • Service Layer
    this handles the calls between the Presenation layer and the Data layer, applying business logic or whatever other checksums may be necessary (and keeping it away from the presentation layer)
  • Data Layer
    Here your Entities reside and the context to the database.

For the sake of simplicity, you can keep this in one project, but if this becomes a big application you probably want to refactor it out in to separated libraries.

Now, as far as how to refactor your situation now, we add the service layer in there. I like to use interfaces so it makes things easy to test later on I can implement a "dummy" IWhateverService when I go to unit test, but keep the current implementation when running the actual application. Then you implement the interface to interface with the data and return what you need (or perform whatever actions are necessary [CRUD]). e.g.

public interface IEventService
{
    IEnumerable<Event> GetActive();
}

public class EventService : IEventService
{
    private readonly Entities entities;
    public EventService(Entities entities)
    {
        this.entities = entities;
    }
    public IEnumerable<Event> GetActive()
    {
        DateTime now = DateTime.Today;
        return this.entities.Events
            .Where(x => !x.removed)
            .Where(x => x.start_date <= now && x.end_date >= now)
            .AsEnumerable();
    }
}

Now that we have our service, we can plumb it through to the controller:

public class EventsController : Controller
{
    private readonly IEventService eventService;

    public EventsService()
    {
        this.eventsService = new EventsService(new Entities());
    }

    // action that gets and views the active events
    public ActionResult Active()
    {
        var activeEvents = this.eventsService.Getactive();
        return View(activeEvents);
    }
}

As the project evolves, you can update your IEventService with CRUD operations (like I mentioned earlier):

public interface IEventService
{
    IEnumerable<Event> All { get; }

    void AddOrUpdateEvent(Event event);
    IEnumerable<Event> GetActive();
    void RemoveEvent(Event event);
}

Of course plumbing it through to EventService, then finally having that access within the EventsController.

To take it [several] steps further, you can look at Dependency Injection where you specify (one time) how to build an IEventsService then, when you need it, pass it as an argument to your controller's constructor (like so):

public OtherController : Controller
{
    private readonly IUserService;
    private IEventService eventService;

    public OtherController(IUserService userService, IEventService eventService)
    {
        this.userService = userService;
        this.eventService = eventService;
    }

    /* actions */
}

Then, you can use something like Castle Windsor, ninject, or any of the other solutions that would involve a single map to these interfaces and then (magically) provide them to your controller's constructor for use. To give an example, here's a Castlewindsor configuration:

container.Register(
    Component.For<IEventService>().ImplementedBy<EventService>()
        .LifestyleSingleton()
);

Which essentially says that every time I need IEventService supply EventService.




回答2:


May be you can use a partial class to achieve this.

Interface:

interface IMethods<T>
{
    IEnumerable<T> ActiveItems();
}

Partial Class:

partial class Event :IMethods<Event>
{
    public IEnumerable<Event> ActiveItems()
    {
        try
        {
            using (var db = new Entities())
            {
                DateTime now = DateTime.Today;
                return db.Events.Where(b => !b.removed && b.start_date <= now && b.end_date >= now);
            }
        }
        catch (Exception)
        {
            return null;
        }

    }
}

Test Method:

 public class TestClass
{
    public void MyTest()
    {
        var ativevnts = new Event().ActiveItems();
    }
}


来源:https://stackoverflow.com/questions/17882737/dry-entity-framework-search-call

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!