[Translator's note] Entity Framework 1.0 has been released for a while, but few people feel it useful. One of the major reasons may be that Poco is not supported. You must know that Entity Framework 1.0 inherits your entity from the base class of EF. For many people, especially those who advocate DDD, it is a difficult medicine to swallow. Microsoft developers once provided a poco adapter, but it is not a formal practice. Visual Studio 2010 and. Net 4.0 provide many new features, which are exciting and eager to come back to. NET 1.0. Spring (it should be summer). You finally came back (although it was cold in the morning/evening ). The Entity Framework 4.0 provides poco support. For many users, this is the time to start using the Entity Framework. The blog of the ADO. Net team posted some posts about EF and poco, which is worth reading.
[Original address] poco in the Entity Framework: Part 1-the experience
[Original article posting date] 21 May 09 pm
Last week, I mentioned in my poco overview that POCO entity support is one of the new features we added to Entity Framework 4.0. This week, I will discuss in depth the details of Poco support in Entity Framework 4.0.
There are many things to discuss, including
- Overall poco experience in Entity Framework 4.0
- Poco change tracking
- Link trimming
- Complex types
- Delayed (lazy) Loading and explicit Loading
- Best practices
In this post, I will focus on the overall experience, so that you can immediately enable poco support in Entity Framework 4.0. I will use a simple example to demonstrate how to Use POCO in Entity Framework 4.0. I will use the northwind database. In the subsequent posts, I will continue to build on the basis of this example.
Step 1: Create a model and disable the defaultCodeGenerate
Although poco allows you to write your own entity classes in a transparent and persistent manner, it is still necessary to "access" persistence and EF metadata so that your POCO entity can be recovered from the database, and persisted to the database. To achieve this, you still need to use the Entity Framework designer to create an Entity Data Model, or provide CSDL exactly the same as that generated in Entity Framework 3.5, SSDL and MSL metadata files. So, first, I will use the ADO. Net Object Data Model Wizard (Entity Data Model Wizard) to generate an edmx.
- Create a class library project to define your poco type. I will name itNorthwindmodel. This project is unrelated to durability and has no dependence on the Entity Framework.
- Create a class library project that contains the persistence-related code.Northwinddata. In additionNorthwindmodelThe project is dependent on the object framework (system. Data. entity.
- InNorthwinddataProjectAdd new item, Add aNorthwind. edmx"ADO. Net object data model (this will automatically add dependencies on the object framework in the project ).
- Select "generate from database" to create a model for the northwind database.
- Select onlyCategoriesAndProductsThese two tables you are interested in are included in your object data model.
At this point, the Entity Data model that can be used by me has been generated, but before writing code, there is also a last step: disable code generation. After all, you are interested in poco. please remove the responsibility fromNorthwind. edmxGenerateEntityobjectCodeCustom Tool(Custom tool)Attribute, which will disable the code generation of your model.
Now we can write the POCO entity.
Step 2: Write yourPocoEntity
I will write simple poco entities for category and product, and these classes will be addedNorthwindmodelProject. Note: What I show here should not be considered as a best practice. The intention here is just the simplest example to demonstrate how to work. In the future, we will expand and customize these examples as needed, and then use them based on them.RepositoryAndUnit of workMode for further expansion.
Here is the sample code of the category object:
Public class category
{
Public int categoryid {Get; set ;}
Public String categoryname {Get; set ;}
Public String description {Get; set ;}
Public byte [] picture {Get; set ;}
Public list <product> Products {Get; set ;}
}
Note: In the model, I define attributes for both scalar fields and navigation attributes. The navigation property in the model is converted to list <product>.
Similarly, the product entity can be written as follows:
Public class product
{
Public int productid {Get; set ;}
Public String productname {Get; set ;}
Public int supplierid {Get; set ;}
Public String quantityperunit {Get; set ;}
Public decimal unitprice {Get; set ;}
Public int16 unitsinstock {Get; set ;}
Public int16 unitsonorder {Get; set ;}
Public int16 reorderlevel {Get; set ;}
Public bool discontinued {Get; set ;}
Public category {Get; set ;}
}
In this example,ProductOnly oneCategoryTherefore, we have a pairCategory(RatherCategoryIsList <t>Set ).
Step 3: Compile your object framework context
To combine all these things together, the last thing I have to do is provide a context implementation (just like what you get when using the default code to generateObjectcontext). Context is the glue that brings persistence consciousness into your application. It allows you to write queries, restore entities, and store changes back to the database. The context will beNorthwinddataPart of the project.
For the sake of simplicity, I included our context class in the same class library project that contains the object type, but in our discussions suchRepositoryAndUnit of workIn other mode, we will make such a setting, that is, you will have a pure poco class library without any persistence-related things.
Here is a simple context implementation for our scenario:
Public class northwindcontext: objectcontext
{
Public northwindcontext (): Base ("name = northwindentities ",
"Northwindentities ")
{
_ Categories = createobjectset <Category> ();
_ Products = createobjectset <product> ();
}
Public objectset <Category> categories
{
Get
{
Return _ categories;
}
}
Private objectset <Category> _ categories;
Public objectset <product> Products
{
Get
{
Return _ products;
}
}
Private objectset <product> _ products;
}
Note,Objectset<T> Is a special one introduced in Entity Framework 4.0.Objectquery<T>.
That's easy! Now you have a pure POCO entity, a simple context that allows you to write a query like this:
Northwindcontext DB = new northwindcontext ();
VaR beverages = from P in db. Products
Where p. Category. categoryname = "beverages"
Select P;
The entities recovered from the database are purely poco entities. You can make changes to these entities and save the changes to the database.EntityobjectOrIpocoEntities are very similar. You will get all the services provided by the Entity Framework. The only difference is that you are currently using pure poco entities.
In our simplified example, there are still countless possibilities for improvement. But before that, I want to solve some basic problems first.
In usePocoDo I need an object data model before?
Yes, the POCO support in Entity Framework 4.0 only removes the need for persistence-specific attention in your object class. However, you still need to provide the CSDL, SSDL, and MSL metadata so that the Entity Framework can combine your entities and metadata to allow you to access data. We are also developing another thing that allows you to develop a real "code-First" without the need for a pre-defined edmx model. This featureCommunityThe preview version will be released online within a few months. Once we have the opportunity, we will add it to the Entity Framework. As always, your feedback is extremely useful to us.
Can I always write these entities and context by hand?
No, Entity Framework 4.0 has a very powerful and flexible Code Generation Mechanism Based on T4 (Alex discussed on this blog ). You can provide your own templates, allowing you to build entities in the way you choose. We are still working to provide some standard templates to generate poco entities for you.
UsePocoHow does metadata map objects?
In Entity Framework 3.5EntityobjectAndIpocoAll objects depend on attributes to modify and map object types and attributes to elements corresponding to the conceptual model. Entity Framework 4.0 introduces a convention-based ing to allow ing of entity types, attributes, complex types, and relationships to a conceptual model without explicit modifiers. A simple rule is that the object type name, attribute name, and complex type name used in your poco class must match the corresponding names defined in the conceptual model. The namespace name is not taken into consideration. The namespace definitions in the class do not need to be consistent with those in the conceptual model.
All attributes in my object class must be public.GettersAndSetters?
You can use any access control Modifier on your poco attributes, As long as any attributes mapped are not virtual, and you do not need the support of partial trust. When running with local trust, you have specific requirements on the visibility of your object class Access Control modifier. We will provide detailed documentation on the complete set of access control modifiers supported when local trust is involved.
Which set types are supported for set-based navigation attributes?
AnyIcollection <t>All types are supported. If youIcollection <t>If a field of type is not initialized with a specific type, the object set is restored from the database.List <t>.
Can I have a one-way relationship? For exampleProductClass hasCategoryAttribute, but inCategoryClass.ProductsSet.
Yes, this is supported. The only restriction is that your object type must reflect what is defined in the model. If you do not want to have navigation attributes corresponding to one side of the link, you need to remove them from the model.
PocoDoes it support delayed (lazy) loading?
Yes, Poco supports delayed (lazy) loading by using the proxy type. These proxy types provide automatic lazy loading behavior on top of your poco class. We will discuss this in detail when we talk about delayed loading. Before that, we can also use"Include"To achieve the early loading (eager loading), like this:
VaR beveragecategory = (from C in context. Categories
. Include ("Products ")
Where C. categoryname = "beverages"
Select c). Single ();
I don't need to do this if I want to use a delayed (lazy) load. We will discuss this when discussing the proxy.
Fix-up relationship
You need to know two types of trim: 1) TRIM when querying, 2) TRIM when modifying your entities/relationships.
Query trimming
The query is trimmed in the sameObjectcontextWhen different queries are used to load related entities. For example, if I query a classification instanceBeverages(Beverage)", And then query a product instance"Chai"(InBeveragesIn the category), I wantChai. CategoryPointBeveragesYou do not need to do additional work.
This is automatic today and already works.
For your entity/Trim when the link is modified
This is the relationship trim between two entities when adding/removing entities related to another entity or changing the relationship. Imagine an example:"Diet Chai"When using a new product, I wantBeveragesClassification.
In Entity Framework 4.0 beta1, in this case, the POCO object cannot be automatically trimmed. When dealing with changes in the relationship between entities, you need to confirm that your poco type contains the logic for correct link trimming at both ends of the relationship.
For example, in my northwind exampleCategoryThe following method is defined to support adding/removing orders.
Public void addproduct (product P)
{
If (products = NULL)
{
Products = new list <product> ();
}
If (! Products. Contains (p ))
{
Products. Add (P );
}
P. Category = this;
}
In general, using a mode like this to support adding/removing related items is better than using a relational set to Add/Remove related entities. You can also change the getter/setter of the set actually supported by EF to private or internal access control to support more fine-grained access, but as mentioned above, some of these items depend on whether you need local trust to support such requirements.
We have discussed the overall poco experience in this "Brief Summary. There are many other things to discuss. I will continue this discussion next week. At the same time, please take a look at the complete solution in the attachment, if you are interested in the corresponding routine code of all the concepts we discuss here. Remember, you must install a local northwind database on the machine that runs this routine.
In the next post, we will take a look at the complex types, change tracking, proxy, lazy loading and early loading. Before that, read the POCO documentation on msdn to learn more about poco support in Entity Framework 4.0.
Please let us know your thoughts!
Faisal Hamood
Entity Framework Program Manager
Attachment: northwindpocosamplepart1.zip
Complex types)
The complex types in poco supportEntityobjectThe complex types in the object support the same. All you need to do is declare them as poco classes, and then use and declare their attributes in your poco entities.
For example, here isInventorydetailComplex types represent a part of my product entity:
Public class inventorydetail
{
Public int16 unitsinstock {Get; set ;}
Public int16 unitsonorder {Get; set ;}
Public int16 reorderlevel {Get; set ;}
}
Put myProductClass to include an attribute of this type, used to combine several fields related to inventory details:
Public class product
{
Public int productid {Get; set ;}
Public String productname {Get; set ;}
Public int supplierid {Get; set ;}
Public String quantityperunit {Get; set ;}
Public decimal unitprice {Get; set ;}
Public inventorydetail {Get; set ;}
Public bool discontinued {Get; set ;}
Public category {Get; set ;}
}
Then you can do everything you previously can do for complex types. This is an example of a query:
VaR outofstockproducts = from C in context. Products
Where C. inventorydetail. unitsinstock = 0
Select C;
As you can see, the support for complex types in Poco is very straightforward. But when using complex types in poco, you need to remember several things:
- You must define a complex type as a class. struct is not supported.
- In your complex type class, you cannot use inheritance.
Since we are discussing complex types, I want to mention another thing. Do you know that the Entity Framework designer in Visual Studio 2010 supports declarations of complex types?
In Visual Studio 2008, you can only manually add the declaration of complex types to CSDL, but with the introduction of the complex types supported by the designer in Visual Studio 2010, all of this has become a history.
Even cooler, because Visual Studio 2010 supports multi-targeting, you can also use this function when developing applications targeting. NET Framework 3.5 and using Entity Framework 3.5!
Delayed/lazy loading
In my late loading overview article published two weeks ago, I mentioned that the Entity Framework now supports delayed loading. By default, the code is generated based onEntityobjectObject Type will provide delayed loading, naturally not surprising. If you want to know whether the POCO object also supports delayed loading, you will be very happy to know that you can also get delayed loading support in Poco.
To support delayed loading in poco entities, you need to do two things:
- Declare the property you want to load in a lazy mannerVirtual, These attributes can be any implementedIcollection <t>Or they can represent references to the 1/0 .. 1 relationship.
For example, it is updated here.CategoryI changed some code of the object class to support delayed loading:
Public class category
{
Public int categoryid {Get; set ;}
Public String categoryname {Get; set ;}
Public String description {Get; set ;}
Public byte [] picture {Get; set ;}
Public Virtual list <product> Products {Get; set ;}
...
2. Enable the delayed loading option in the context:
Context. contextoptions. deferredloadingenabled = true;
Now you can get the POCO-Type Automatic delayed loading instead of doing anything else.
So how does this stuff work, and how does it work at the underlying layer?
This is because I mark the property of the collection typeVirtualThis allows the entity framework to provideProxy (Proxy)Instance, which is the proxy that implements automatic delayed loading. This proxy instance is based on a self-inherited POCO entity class type, so all the features you provide are retained. From the developer's perspective, even if delayed loading may be a requirement, this allows you to write transparent and persistent code.
If you check the actual instance in the debugger, you will see that the underlying type of the instance is different from the type previously declared:
Although the Entity Framework tries its best to provide automatic delayed loading with minimal friction, when processing instances you want to add or attach manually generated instances, or when you serialize/serialize instances, this is something you need to know.
IsPocoManually generate proxy instances for entities
To allow the generation of proxy instances that can be added or attached, you can use the Createobject factory method on objectcontext to generate an object instance:
CATEGORY Category = context. Createobject <Category> ();
Remember to useCreateobject.
Use Change tracking proxies to provide more effective change tracking
The standard poco objects we have discussed so far rely on Snapshot-based change tracking, that is, the Entity Framework keeps snapshots of values and relationships before changes to the entity, in this way, you can compare it with the current value when saving. However, the cost of this comparison is quite large, if compared with the method of object change tracking based on entityobject.
There is another type of proxy that allows you to get better performance of change tracking when using poco entities.
If you are familiar with the ipoco interface, you knowIentitywithchangetrackerIs one of the interfaces that require you to implement and provide change notifications to the object framework in the class.
Change tracking agentThis function is inherited from your poco object class and provided to you at runtime, without requiring you to implement the ipoco interface yourself.
In many ways, if you use this method, you get both the fish and the bear's paw: You get the transparent persistence of the POCO class, and you also get the change tracking.Entityobject/IpocoPerformance.
To get the change tracking proxy, the basic rule is that your class must be public, non-abstract or non-sealed ). Your class must implement public virtual getters/setters for all attributes to be persistent. Finally, you must strictly declare the link navigation Attribute Based on the set as icollection <t>. They cannot be specific implementations or other interfaces inherited from icollection <t> (different from delayed loading proxy ).
Here is myProductPoco class example, it will provide me with more effective agent-based change tracking at runtime:
Public class product
{
Public Virtual int productid {Get; set ;}
Public Virtual string productname {Get; set ;}
Public Virtual int supplierid {Get; set ;}
Public Virtual string quantityperunit {Get; set ;}
Public Virtual decimal unitprice {Get; set ;}
Public Virtual inventorydetail {Get; set ;}
Public Virtual bool discontinued {Get; set ;}
Public Virtual category {Get; set ;}
}
Again, remember that if you want to add or attach an object to the context, you must useCreateobjectTo generate a proxy instance. However, purely poco entities independent of proxies and proxy-based entities can coexist. Createobject is required only when proxy-based entities are involved.
If you wantPocoThe type enables delayed loading and better change tracking at the same time. What should I do?
These two items are not mutually exclusive. You do not have to choose between the delayed loading agent and the change tracking agent. If you want delayed loading and effective change tracking, you only need to follow the rules of the change tracking agent and enable the delayed loading option. The change tracking agent will provide you with delayed loading, if the delayed loading option is enabled.
Explicit Loading
This delayed loading feature is really great, but many of you probably want to have full control over how you load related entities. You may even choose to take the pure poco path, instead of having to resort to any function that automatic proxy generation can provide to you.
This is completely acceptable (in many cases it may be a better method), you can use explicit link loading, fully control how you query data in the database.
In pocoExplicit Loading, There are two options:
One is to useObjectcontext. loadproperty, Set the name of the navigation attribute you want to load:
Context. loadproperty (beveragescategory, "Products ");
This is feasible, but you can see that this is not type safe ). If I do not have the correct name for the navigation attribute, I will get a runtime exception.
Some of you prefer this:
Context. loadproperty (beveragescategory, c => C. products );
I can use lambda expressions to specify the attributes I want to explicitly load, which provides better type security.
The above is all the content I plan to discuss in this second post. But there will be more in the future. In the last article of this series, we will discuss how to deal with pure poco (non-proxy) instance and several things you need to know when your object graph is consistent with the object state manager. We will also discuss multiple variants of the savechanges method you might want to know.
At the same time, please take a look at the sample code I have updated, including some of the things we have discussed in this post.
Faisal Hamood
Entity Framework Program Manager
Attachment: northwindpocosamplepart2.zip