Today we mainly introduce a high-level part of EF Code First : Value object, which is called the values objects in Chinese translation.
The so-called value objects are classes that have no life cycle and no unique identifiers on the business logic. Which classes are entity and which classes are value object are not fixed, depending on the specific business logic. For example, customer this class, if in the CRM system, it is the most important information, we need to track its state, management of its life cycle. However, in other systems, customer information may represent only one name and some other attributes.
Below I have a requirement that our order system has a customer class. In our previous example, the Address property of the customer class is a string. Now our business logic has changed, we need to classify the address information to display and save, the address information into the country, province, city, street and number, and zip code. In our business, address information is only a collection of attributes, does not need to track its life cycle, and there is no unique identifier in the business. So we define it as a value Object:
Public classAddress
{
PublicstringCountry {Get;Set; }
PublicstringProvince {Get;Set; }
PublicstringCity {Get;Set; }
Publicstringstreetaddress {Get;Set; }
PublicstringZipCode {Get;Set; }
}
To have the entity Framework Code first recognize the value object by default, our class must have three conditions:
1. The class of a value object cannot have a primary key.
2. The class of a value object can only contain properties of the. NET underlying type.
3. A class that uses a value object can contain only one instance of a value object and cannot use a collection of value objects.
Then we need to change our customer class and use the address value object to replace the previous string.
PublicclassCustomer
{
PublicstringIdcardnumber {Get;Set; }
Public stringCustomerName {Get;Set; }
PublicstringGender {Get;Set; }
PublicAddress Address {Get;Set; }
PublicstringPhoneNumber {Get;Set; }
}
If the value object does not meet the three default value object recognition criteria, we need to declare the address to be a value object in the Onmodelcreating method of our custom DbContext class.
Modelbuilder.complextype<address> ();
Here's a test method to see how he generated the table to the database:
[TestMethod]
PublicvoidCanaddnewcustomerwithaddress ()
{
Ordersystemcontext unitofwork =NewOrdersystemcontext ();
Customerrepository repository =NewCustomerrepository (unitofwork);
Customer Newcustomer =NewCustomer () {idcardnumber ="120104198106072518", CustomerName ="Alex", Gender ="M", PhoneNumber ="Test"}
Address customeraddress =NewAddress {country =" China", province ="Tianjin", City ="Tianjin", streetaddress ="Crown Plaza", ZipCode ="300308"};
newcustomer.address = CustomerAddress;
Repository. Addnewcustomer (Newcustomer);
Unitofwork.commitchanges ();
}
We use the Dropcreateorderdatabasewithseedvaluealways custom database initialization class, which inserts the underlying data, to reestablish the database each time the test method is executed.
[TestInitialize]
PublicvoidInitializecustomerrepositorytest ()
{
Database.setinitializer (NewDropcreateorderdatabasewithseedvaluealways ());
}
You can see the resulting corresponding table structure as follows:
As we can see from the above, we can see that code first defaults to the address value object's properties as a column of the Customers table. The name of the column defaults to the name of the value object class + "_" + the name of the value object property.
We can also change this way:
Publicclassaddresscomplextypeconfiguration:complextypeconfiguration<address>
{
PublicAddresscomplextypeconfiguration ()
{
Property (A = A.country). Hascolumnname ("Country"). Hasmaxlength ( -);
Property (A = A.province). Hascolumnname ("Province"). Hasmaxlength ( -);
Property (A = a.city). Hascolumnname (" City"). Hasmaxlength ( -);
Property (A = a.streetaddress). Hascolumnname ("streetaddress"). Hasmaxlength ( -);
Property (A = A.zipcode). Hascolumnname ("ZipCode"). Hasmaxlength (6);
}
}
We pass Hascolumnname This method , you can change the name of the column that corresponds to the property. The Entity Framework Code first uses the name of the property in the class as the name of the column by default.
Summary: This chapter is mainly about the fluent API configuration mapping, how to generate the corresponding database table structure.
Code First05--codefirst Medium Value Object