0

In my projects I often don't have a separate Data Access Layer, but I like to add some raw SQL methods to my Entities for performance reasons.

So I have a MassUpdateSomethingAndPersist() in one of my Entity classes. To do the mass update I need to call dbContext.Database.ExecuteSqlCommand from within the Entity. But of course I need a reference to the DbContext first.

Question

Is it possible to get the DbContext from within the Entity? Using reflection for this is not an issue for me, because these are relatively heavy operations anyway.

Dirk Boer
  • 8,522
  • 13
  • 63
  • 111

3 Answers3

4

I think what you are trying to do, indicates an OO design flaw. It shouldn't be the Entity classes' responsibility to update the database. That's the responsibility of the DBContext.

So

  1. No, it is not possible, and
  2. Wanting to do it, indicates a design flaw (probably)

If you want to execute custom SQL, you should execute it from the caller, on the context, not from within the entity itself.

An example can be found here: DBContext Native SQL Queries.

Community
  • 1
  • 1
Erik A. Brandstadmoen
  • 10,430
  • 2
  • 37
  • 55
  • 1
    Do you have some good source that can explain me why this is such a bad practice (for middlesized projects) - as long as it is clear by the method that it persists to the database? Just working with Entities pretending there is no (slow) database operations behind it has proven to be not working for my projects. – Dirk Boer Sep 08 '13 at 20:30
  • Well, this is really just good OO practice. Keywords: SRP, Separation of Concerns, Dependency Inversion Principle. Read up on the SOLID principles (e.g. here: http://www.codeproject.com/Articles/60845/The-S-O-L-I-D-Object-Oriented-Programming-OOP-Prin). Your suggestion would at least violate the Dependency Inversion and Single Responsibility principles. – Erik A. Brandstadmoen Sep 08 '13 at 20:37
  • Yeah I know SOLID, but I like to see some practical examples. Like I said before - pretending there is no (slow) database operations behind Entities has **proven** to be not working for my projects. Adding (well-named) methods that executes in some very specific cases raw SQL hasn't proven to be a problem for me **yet**. Maybe a good topic for a different question :) – Dirk Boer Sep 08 '13 at 20:50
  • 1
    Well, of course you can add custom SQL, but you should add it to the DBContext instead of the entities themselves. The entities should be totally ignorant of persistance mechanism. They should be pure .NET classes with properties on them, and persistance should be handled by the DbContext. – Erik A. Brandstadmoen Sep 08 '13 at 20:52
  • Adding quite some methods like MassUpdateThis() and MassUpdateThat() would also violate the Single Responsibility Principle in my opinion. "entities should be totally ignorant" - I know this is the general opinion, but I'm still wondering 'why'. Having them for 95% ignorant so you can test the business logic makes sense - but having a MassUpdateSomethingAndPersist() method in there doesn't refrain me from making tests for all the other functionality in the Entity - the only thing I can't easily test is that MassUpdate. – Dirk Boer Sep 09 '13 at 00:16
  • 1
    Ps: thanks for taking all the effort for answering my questions! Maybe you can remove point 1 though, because that seems to be wrong - see the accepted answer. – Dirk Boer Sep 09 '13 at 00:20
  • I don't really see how the accepted answer helps you access the dbContext from within the entity itself. Boris B.'s answer does achieve what you want, but it requires all objects inherit from a particular class to have a reference to the context, and it kind of defeats the intention of EF, with POCO's as entities, and persistence resolved "elsewhere", IMHO. – Erik A. Brandstadmoen Sep 09 '13 at 07:06
  • From within my entity I can do `var context = MyDbContext.FromObject(this)`. – Dirk Boer Sep 09 '13 at 08:57
1

It is possible:

((IObjectContextAdapter)dbContext).ObjectContext.ObjectMaterialized += (sender, e) => 
{
    (e.Entity as IEntityWithDbContext).DbContext = dbContext;
}

public interface IEntityWithDbContext
{
    public DbContext DbContext { get; set; }
}

public partial class User : IEntityWithDbContext
{
    public IEntityWithDbContext.DbContext DbContext { get; set; }
}

But it's still a design flaw...

Given your description you should easily be able to make MassUpdateSomethingAndPersist() a method of the DbContext (i.e. MassUpdateSomethingAndPersist(something)).

Boris B.
  • 4,933
  • 1
  • 28
  • 59
  • Problem is that because I work (apparently?) with relative large datasets, is that I have quite a lot of these methods. Adding them all to the DbContext **really** goes against the 'Single Responsibility' principle in my opinion. Making a separate class per Entity just for these 'mass updates' seems like a lot of extra overhead to me, while I don't really see it solving any direct problems (as long as it's clear that the method also persists it to the database). – Dirk Boer Sep 08 '13 at 23:20
0

In Entity Framework, you should follow the Domain Driven Design (DDD) concept of an Entity, which is that it is always persistence ignorant. If you break this pattern, as you are asking, then you may find it extremely difficult to do proper unit testing.

The pattern where an object modifies its own representation in the database is known as the Active Record Pattern, and isn't something that is encouraged for Entity Framework. If you want to use the Active Record Pattern, then look into a framework that is designed for it - such as Castle ActiveRecord.

Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Unit Testing is rather easy if you just change two fields on an Entity. Problem is that in my real life application I sometimes need to update hundreds of properties at the same time. Doing this without SQL is not possible, so the user of the code can't work 'persistence ignorant' anyway. Most of my code will still be persistence ignorant, but sometimes I *really* need a MassUpdateAndPersist(). – Dirk Boer Sep 08 '13 at 23:26
  • That Castle ActiveRecord looks interesting though, so I can take a look if that helps me further. – Dirk Boer Sep 08 '13 at 23:28
  • I don't see how number of fields has anything to do with it. You simply update as much of your entity as you need to, and pass your updated entity to be saved. One big save is going to be more efficient than hundreds of little ones. – Matt Johnson-Pint Sep 08 '13 at 23:40
  • Also, I wasn't advocating for Castle Active Record, I'm just saying that it is a framework designed for that pattern. Personally, I would choose to stay away from the Active Record pattern entirely. [Here is a decent article](http://www.mehdi-khalili.com/orm-anti-patterns-part-1-active-record) about why it can get you into trouble. – Matt Johnson-Pint Sep 08 '13 at 23:50
  • Sorry to be unclear - I meant of course hundreds of properties of *different* Entities. As in UPDATE Match SET Points = 10 WHERE Winner = 'Lolcat'. – Dirk Boer Sep 09 '13 at 00:06
  • That type of operation belongs in a *repository*. Search for info about the repository pattern with EF and you'll find plenty of examples. – Matt Johnson-Pint Sep 09 '13 at 02:13