Entity Framework formation tour-using Unity object dependency injection to optimize Entity Framework (2), entityunity

Source: Internet
Author: User

Entity Framework formation tour-using Unity object dependency injection to optimize Entity Framework (2), entityunity

In the first article of this series, the journey to the formation of Entity Framework-Entity Framework based on the generic warehousing model (1) this section describes some basic knowledge about the Entity Framework object Framework and a simple generic-based storage Framework. The example also shows the prototype of an object Framework application, this article will continue to introduce this topic, continue to deepen the Entity Framework knowledge, and continuously optimize the Entity Framework of this warehousing model. It will mainly introduce the construction of the business logic layer, and Dynamic Object Registration using Unity and reflection.

1. Adjust the EDMX File Location

From the previous example, we can see that the object Framework Structure of the warehouse model described in this article is as follows.

But in fact, the example above is a bit idealistic, because we know that [ADO. NET Object Data Model] The generated EDMX file automatically generates the context SqlserverContext for data access and several table entity classes. The specific effect is as follows.

We ideologically put it in the DAL directory, under the Entity directory, is actually not possible, at least there is a conflict.

So how can we handle these automatically generated content in a reasonable manner? In addition, we have upgraded it to the business layer. How does the BLL layer process data access objects and how does it build data access objects? With these problems, we will analyze the content of this framework step by step.

In order to give the object class a friendly name, we remove the table name prefix by the way, as shown in the EDMX figure below.

To better utilize the code generation of the EDMX file, we moved the entire file to the Entity directory, as shown below.

This is equivalent to moving all the data access context and Entity class code into the Entity namespace. Although it may not feel good, we should first let it run, the specific details are further optimized.

2. Design of the business logic layer

Let's take a look at the business logic layer (including the business logic interface layer), which is similar to the data access layer. We will build it as follows.

1) business logic interface layer

/// <Summary> /// basic class interface of the business logic layer /// </summary> /// <typeparam name = "T"> Object Type </typeparam> public interface IBaseBLL <T> where T: class {T Get (object id); IList <T> GetAll (Expression <Func <T, bool> whereCondition); IList <T> GetAll ();}

2) business logic layer implementation

/// <Summary> /// business logic base class /// </summary> /// <typeparam name = "T"> Object Type </typeparam> public abstract class BaseBLL <T>: IBaseBLL <T> where T: class {protected IBaseDAL <T> baseDAL {get; set;} public BaseBLL (IBaseDAL <T> dal) {this. baseDAL = dal;} public T Get (object id) {return baseDAL. get (id);} public IList <T> GetAll (Expression <Func <T, bool> whereCondition) {return baseDAL. getAll (whereCondition);} public IList <T> GetAll () {return baseDAL. getAll ();}}

3) logical interface layer of the Business Object Class

/// <Summary> /// City business object interface /// </summary> public interface ICityBLL: IBaseBLL <City> {}

4) logical layer implementation of business objects

/// <Summary> // City business object // </summary> public class CityBLL: BaseBLL <City> {protected ICityDAL; public CityBLL (ICityDAL ): base (dal) {this. dal = dal ;}}

The above section describes the implementation of the business logic layer. However, we can see a problem: whether it is the logic layer base class or the logic object of specific business objects, no default constructor.You cannot use new to create an object!

This is a serious problem. How can we avoid this problem, so that our business object class can use the default function and use new to create objects? Here we need to introduce the IOC container practice, that is, using Microsoft Unity to inject and use objects.

3. Use Unity to implement object dependency Injection

1) Brief Introduction to Unity

Unity is a lightweight and scalable dependency injection container implemented by the Microsoft patterns & practices Group in C #. It facilitates developers to build loosely coupled applications,

It has the following advantages:

1. simplified object creation, especially for hierarchical object structures and dependencies;

2. Abstract requirements: allows developers to specify dependencies at runtime or in the configuration file to simplify management of cross-concern points;

3. delayed the time to configure components for containers and increased flexibility;

4. Service positioning capability, enabling customers to store or cache containers;

5. instance and type Interception

The example of Unity dependency injection is easy to understand. The specific code is as follows.

Static void Main (string [] args) {// instantiate a controller IUnityContainer unityContainer = new UnityContainer (); // implement object injection into unityContainer. registerType <IBird, Swallow> (); IBird bird = unityContainer. resolve <IBird> (); bird. say ();}

This Unity object can be added through Nuget. After being added, the corresponding Assembly reference will be available in the project.

 

2) Introduce Unity to inject data access objects and improve the implementation of the logic layer.

After learning about the use of Unity, we can build an IOC container in the BaseBLL object base class and register the corresponding data access layer object during the initialization of the container, as shown below.

/// <Summary> /// business logic base class /// </summary> /// <typeparam name = "T"> Object Type </typeparam> public abstract class BaseBLL <T>: IBaseBLL <T> where T: class {private static readonly object syncRoot = new Object (); protected IBaseDAL <T> baseDAL {get; set ;}Protected IUnityContainer container {get; set ;}/// <Summary> /// default constructor. /// The cache container is obtained by default. If no container exists, create the container and register the required interface implementation. /// </Summary> public BaseBLL () {lock (syncRoot ){Container= DALFactory. Instance. Container;If (container = null) {throw new ArgumentNullException ("container", "container not initialized ");}}}

Well, by default, In the DALFactory class, we press the required data access object during its instantiation, in this way, we can implement the call in the specific business object logic class, as shown in the following code.

/// <Summary> // City business object // </summary> public class CityBLL: BaseBLL <City> {protected ICityDAL; public CityBLL (){Dal= Container. Resolve <ICityDAL>();BaseDAL = dal;} public CityBLL (ICityDAL dal): base (dal) {this. dal = dal ;}}

If we don't care about the architecture details in DALFactory, the injection of the objects completed by this framework can be used normally.

However, let's take a look at its implementation details. We constructed the IOC container through the singleton mode (hunger mode) and injected the corresponding DAL object.

/// <Summary> /// the construction factory of the data access layer interface of the object framework. /// </Summary> public class DALFactory {// common local variable private static Hashtable objCache = new Hashtable (); private static object syncRoot = new Object (); private static DALFactory m_Instance = null; // <summary> // The IOC container, which can be called to obtain the corresponding interface instance. /// </Summary> public IUnityContainer Container {get; set ;} /// <summary> /// create or obtain the Instance of the corresponding business class from the cache // </summary> public static DALFactory Instance {get {if (m_Instance = null) {lock (syncRoot) {if (m_Instance = null) {m_Instance = new DALFactory (); // initialize the registration interface m_Instance.Container = new UnityContainer (); // manually load m_Instance.Container.RegisterType <ICityDAL, CityDAL> (); m_Instance.Container.RegisterType <IProvinceDAL, ProvinceDAL> () ;}}} return m_Instance ;}}

OK. Through the above Unity, we have implemented object injection and usage. The specific form call code is as follows.

Private void btnCity_Click (object sender, EventArgs e) {DateTime dt = DateTime. now; CityBLL bll = new CityBLL (); var list = bll. getAll (); this. dataGridView1.DataSource = list; Console. writeLine ("time spent: {0}", DateTime. now. subtract (dt ). totalMilliseconds);} private void txtCityName_KeyUp (object sender, KeyEventArgs e) {DateTime dt = DateTime. now; CityBLL bll = new CityBLL (); if(this.txt CityName. text. trim (). length> 0) {var list = bll. getAll (s => s.CityName.Contains(this.txt CityName. text); this. dataGridView1.DataSource = list;} else {var list = bll. getAll (); this. dataGridView1.DataSource = list;} Console. writeLine ("time spent: {0}", DateTime. now. subtract (dt ). totalMilliseconds );}

The following figure shows the interface effect.

 

4. Use the reflection operation to dynamically register interface objects in the Unity container

In the above example, I don't know if you have noticed that when we use the IOC container of Unity, the registered object is the specified data handler class.

     m_Instance.Container.RegisterType<ICityDAL, CityDAL>();     m_Instance.Container.RegisterType<IProvinceDAL, ProvinceDAL>();

However, this is a bit similar to the hard-coding method. If we have a large number of such data encoding classes in our project and need to be manually added, it is really not an elegant thing.

If the code can automatically register the interface objects we need according to the interface and interface implementation class, how good is it, but can it be done? Yes!

If we execute in the same assembly, we can obtain the corresponding interface layer (IDAL) and interface Implementation Layer (DAL) from the Assembly through the reflection operation) so we can match it for object injection.

Below is the implementation code for dynamically registering the DAL object, as shown below.

/// <Summary> /// use Unity to automatically load the corresponding IDAL interface (DAL layer) /// </summary> /// <param name = "container"> </param> private static void RegisterDAL (IUnityContainer container) {Dictionary <string, type> dictInterface = new Dictionary <string, Type> (); Dictionary <string, Type> dictDAL = new Dictionary <string, Type> (); Assembly currentAssembly = Assembly. getExecutingAssembly (); string dalSuffix = ". DAL "; string interf AceSuffix = ". IDAL "; // compare the interfaces in the program set and the specific interface implementation classes, put them in different dictionary sets foreach (Type objType in currentAssembly. getTypes () {string defaultNamespace = objType. namespace; if (objType. isInterface & defaultNamespace. endsWith (interfaceSuffix) {if (! DictInterface. ContainsKey (objType. FullName) {dictInterface. Add (objType. FullName, objType) ;}} else if (defaultNamespace. EndsWith (dalSuffix) {if (! DictDAL. containsKey (objType. fullName) {dictDAL. add (objType. fullName, objType) ;}}// use the IOC container to register foreach (string key in dictInterface. keys) {Type interfaceType = dictInterface [key]; foreach (string dalKey in dictDAL. keys) {Type dalType = dictDAL [dalKey]; if (interfaceType. isAssignableFrom (dalType) // checks whether the DAL has implemented an interface {container. registerType (interfaceType, dalType );}}}}

With this operation that uses reflection to dynamically inject objects, our implementation in the base class avoids hard encoding inconvenience.

/// <Summary> /// the construction factory of the data access layer interface of the object framework. /// </Summary> public class DALFactory {// common local variable private static Hashtable objCache = new Hashtable (); private static object syncRoot = new Object (); private static DALFactory m_Instance = null; // <summary> // The IOC container, which can be called to obtain the corresponding interface instance. /// </Summary> public IUnityContainer Container {get; set ;} /// <summary> /// create or obtain the Instance of the corresponding business class from the cache // </summary> public static DALFactory Instance {get {if (m_Instance = null) {lock (syncRoot) {if (m_Instance = null) {m_Instance = new DALFactory (); // initialize the registration interface m_Instance.Container = new UnityContainer (); // automatically register the DAL RegisterDAL (m_Instance.Container) according to the agreed rules; // manually load the DAL; // optional <ICityDAL, CityDAL> (); // m_Instance.Container.RegisterType <IProvinceDAL, provinceDAL> () ;}} return m_Instance ;}}

The optimization process of the above framework is centered on the business logic layer. Finally, we have implemented dependency injection for better dynamic objects and provided default constructor for the business logic layer objects, they can obtain and create objects from the IOC container.

But we can see that for an EDMX file, we just put it into the Entity module, and there is no real solution to it. If you need to use this edmx file generation operation every time, I still think the development efficiency is relatively low. What should I do if I need to support multiple databases? It is impossible to create a data operation context. They can be abstracted. They do not seem to be related to a specific database, but only their configuration relationships.

These questions are left for the next article to continue to address the evolution of the Framework. Thank you for your patience. If they are useful, please continue to recommend them. After all, in order to prepare this series, I have spent many days optimizing the Entity Framework of the entire warehouse model from various aspects and leaving a version of demos to sort out my blog.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.