I have an entity framework model called Employee. Whenever I request a list of all Employee rows I first want to make a soap request to get any new employees from another system and update the sql database with them.
Is there some sort of binding that I could apply to the model or would I just have to add another model that calls both and call it instead.
I'm wanting to make it so that I can't call the employee list from the database directly without refreshing it at each place in the razor pages where I call it.
-
hmm i don't think its possibleEwan– Ewan2018年08月27日 17:53:35 +00:00Commented Aug 27, 2018 at 17:53
-
Congrats, you've stumbled across one of the many reasons why EF (and ORMs in general) are not ideal in every situation. ORMs are great if your requirement is "take some DB rows, put them on a screen and maybe edit them:". Well, you've now got a scenario where you need more than that, but there's not a great way to accomplish it without just adding a new helper class with one method that does the service call, waits for it to finish the inserts, then does the EF call. And someone else would have to know that method exists outside of the normal EF flow, so it'll be easy to forget about.GHP– GHP2018年08月27日 20:32:16 +00:00Commented Aug 27, 2018 at 20:32
-
@Graham: This is not a flaw of ORMs in any way. The same issue would apply when OP was using any other logic for data storage. Many solutions exist. When the DAL is abstract into a separate layer, it's perfectly possible to only expose methods which inherently include the additional logic, and prevent any consumer of the DAL assembly to access the database any other way.Flater– Flater2018年08月28日 08:11:31 +00:00Commented Aug 28, 2018 at 8:11
-
@Flater, true, but if you've put EF behind a DAL, you have already sacrificed what is, imho, the main benefit of something like EF, which is the ability to modify and optimize queries right up to the View. If you have a DAL method that loads all Car Objects, but your view just wants to show their names, there's no query benefit to using EF behind the DAL layer. If your page model itself is EF-aware, then the "GetAllCars()" query is translated into just selecting the car names only, at runtime.GHP– GHP2018年08月28日 13:00:13 +00:00Commented Aug 28, 2018 at 13:00
-
@Graham: It seems you misunderstand the purpose of ORMs. Passing the context down to the view is bad practice for many reasons (SRP being the main violation here), and not at all the main benefit of EF. EF's benefit comes from providing a high (but admittedly not complete) conversion from code to SQL. Effectively, a developer using EF (Code First) doesn't need to know one letter of SQL in order to work with their datastore. "This creates, in effect, a "virtual object database" that can be used from within the programming language."Flater– Flater2018年08月28日 13:08:27 +00:00Commented Aug 28, 2018 at 13:08
2 Answers 2
Access modifiers and layer segregation.
Access modifiers (public
, private
, internal
, protected
) make it possible for you to prevent an external caller from calling inner logic directly, and instead force them to use only the logic you have allowed them to access.
If you abstract your data access logic into a separate project/layer (known as the DAL), then you can achieve what you want.
As a simple example:
internal class MyContext : DbContext
{
// ...
}
public class EmployeeRepository
{
public List<Employee> GetEmployees()
{
using(var db = new MyContext())
{
UpdateEmployeeList(db);
return db.Employees.ToList();
}
}
private void UpdateEmployeeList(MyContext db)
{
var externalEmployeeList = GetExternalEmployeeList();
foreach(var employee in externalEmployeeList)
{
db.Add(employee);
}
db.SaveChanges();
}
}
An external caller can only get at the employee data by doing the following:
var employeeRepository = new EmployeeRepository();
var employees = employeeRepository.GetEmployees();
Therefore, it's impossible for them to bypass the additional SOAP call.
However, this does mean that external callers can't have direct access to MyContext
and must always use methods that you've created for them.
In professional codebases, layer segregation is such a common occurrence that this is usually already the case anyway. I would expect any professional codebase to separate its DAL (data acccess layer) into a separate project and not leak its inner dependency (such as EF's DbContext
).
While it's technically possible to do things like intercepting queries, this is not going to be easy to develop nor maintain.
What you're effectively asking for is the following:
I want to force external callers to use my logic (= enforcing the additional SOAP call) instead of just using EF directly.
The logical consequence is that you have to create your logic. This is the DAL I was talking about, it's a project that exists specifically to separate the external caller from EF, and instead force the external caller to use the DAL's logic (which will use EF if and when it wants to - the external caller doesn't get to make the decision).
-
Does the concept of scaffolding from EF objects get broken to the point its not really usable with a DAL? And does that sort of create a custom framework around a framework? Are you starting to diminish the conveniences of EF?Matt Ralston– Matt Ralston2018年08月28日 17:01:11 +00:00Commented Aug 28, 2018 at 17:01
-
1@MattRalston: Yes and no. Yes, when you put a layer between the UI and EF, and wish for the UI to be able to use every feature of EF, then you have to ensure that the DAL exposes every feature. No, because this is implicitly what you're asking for - a way to separate the UI from EF so you can enforce your own business logic. If it were optional (not enforced), then you could give your UI access to both EF directly and your optional DAL, for which you only need to develop additional features. But if you want to enforce using the DAL, you have to force your UI to only use your DAL.Flater– Flater2018年08月29日 07:35:24 +00:00Commented Aug 29, 2018 at 7:35
You could try to intercept the DB-Query. This enables you to execute custom code before the database-query is executed. Check the following link: http://www.entityframeworktutorial.net/EntityFramework6/database-command-interception.aspx
In theory this will work but in my opinion it's a pretty bad way to call a SOAP service, which is completely independent of the DB, in some "random" interceptor.
Instead you should provide a class to your GUI-Models (?) that doesn't give them the EF DataContext itsself but a class that you control. This layer of the application called e.g. dataprovider then decides wether to call the SOAP service and update the db before querying it or not.
This is just a personal opinion of me.