C # changes to monitoring attributes (which toys do big cats have ),

Source: Internet
Author: User

C # changes to monitoring attributes (which toys do big cats have ),
C # Changing the attributes of the monitoring class (which toys are moved by the big cat). After the entity class is created, the attributes assigned to it in the method are assigned, when passed to the underlying method, how does one know which attributes have been assigned a value at the underlying layer. How to monitor the changes of attributes, please refer to the brain hole-wide opening "which little toys have big cats moved"-remember the curve of attribute monitoring to save the country.

When using EF to update database entities. Most of the time, we only want to update one or some fields in the table. Although you can set it to tell the context the field we want to update. However, we usually encapsulate the data persistence layer. Use generic operations. In this case, we cannot know which fields have been modified at the application level.

I have been learning EF recently, and I have encountered this problem. Of course, if you use it directly at the application level, you can set the IsModified status of the field. As follows:
Db. Entry (model). Property (x => x. Token). IsModified = false;
However, this is limited to learning and demo. In formal development, this underlying operation is generally not exposed to the application layer. Will encapsulate the database persistence layer. Then, you can add, delete, modify, and query objects by adding the entity Factory (warehouse) and entity generics.
For details, refer to articles such as Entity Framework-based Repository pattern design.
This type of method has one thing in common. The following code is available during update and deletion:

    public virtual void Update(TEntity TObject)        {            try            {                var entry = Context.Entry(TObject);                Context.Set<TEntity>().Attach(TObject);                entry.State = EntityState.Modified;            }            catch (OptimisticConcurrencyException ex)            {                throw ex;            }        }

Personal Understanding: Update (TEntity TObject) transfers an entity to the method, attaches it to the database context, and marks the data as modified. Then update.
In this case, all fields of the object are updated. Therefore, we need to ensure that this entity is found from the database or corresponds to the database records. There is no problem in the C/S structure, but the problem is in the B/S structure? It is impossible for us to package all fields of the object and send them to the client. Then, the client changes them to the server and calls the repository Method for updates. The simplest way is to change the user password. We only need a user ID and a new password. You can also lock your account by using only one user ID, one lock status, and one lock time. In this way, we cannot package the entire user entity and pass it over. Some people say that you can check the database based on the ID when saving the database, and then append the modified attribute value before updating it. This is back to the problem: only the generic type is available in the repository method, and what you pass when calling the repository update method is an entity type. The repository does not know which object you are and which fields have been updated.
Of course, through the trigger, we know that database updates are first deleted and then inserted, so there is no much difference between updating several fields and updating all columns in the underlying operation.

Now, we can discard the entity generic information such as repository updates. Let's just take a look at how we know what attributes an object has modified when it changes.
Normally, the object length is as follows:

1 /// <summary> 2 /// a specific entity 3 /// </summary> 4 public class AccountEntity: mainEntity 5 {6 /// <summary> 7 // text type 8 /// </summary> 9 public virtual string Account {get; set ;} 10 /// <summary> 11 /// another text attribute 12 /// </summary> 13 public virtual string Password {get; set ;} 14 /// <summary> 15 // number type 16 /// </summary> 17 public virtual int Sex {get; set ;} 18 /// <summary> 19 /// event type 20 /// </summary> 21 public virtual DateTime Birthday {get; set ;} 22 /// <summary> 23 // double-precision floating point number 24 /// </summary> 25 public virtual double Height {get; set ;} 26 /// <summary> 27 /// decimal number 28 /// </summary> 29 public virtual decimal Monery {get; set ;} 30 /// <summary> 31 /// binary 32 /// </summary> 33 public virtual byte [] PublicKey {get; set ;} 34 /// <summary> 35 /// Guid type 36 /// </summary> 37 public virtual Guid AreaId {get; set ;}38}
View Code

When we want to modify the attributes of this object:

Var entity = new accountEntity (); entity. Id = 1; entity. Account = "assign a value to the attribute ';

Then, the object is passed to the underlying layer for operations.

db.Update(entity);

There is no problem at all, but my problem is at the bottom. How can I know that my application layer has modified those attributes? Add another method to tell the underlying layer that I have modified these attributes.

db.Update(entity,"Account");

It seems that there is nothing to do.

But what if I modify the Account but pass the Password in the parameter? Therefore, there should be a set on the entity to store whether the entire attribute has been modified. Then, go to the underlying Update method to retrieve the updated fields for the next step.
Using this idea, I want to add a dictionary to an object:

protected Dictionary<string, dynamic> FieldTracking = new Dictionary<string, dynamic>();

When an attribute value is assigned, it is added to the dictionary. (Of course, this operation will increase program overhead)

FieldTracking ["Account"] = "assigning values to attributes ";

Then, the set in the bottom layer is extracted to identify which fields are modified (which little toys are moved by the big cat ).

Modifying entity attributes

        public virtual string Account        {            get            { return _Account; }            set {                _Account = value;                FieldTracking["Account"] = value;            }        }

All the compiled IL code knows that the attributes in the class will eventually be compiled into two methods: setvalue and getvalue. Then, you can modify the set Method to add FieldTracking ["Account"] = value; you can add attributes to the dictionary when assigning values.

It's easy.


You thought it would be over. If the room is used to compare objects and toys to properties. My big cat is the way to modify object attributes. Do you know how many toys are in my house? When you go home every day, do you know which little toy the big cat is moving? How does one Install GPS for each toy? Hahahahaha, don't worry. It's better to get it back. What? You have to install the purchased package. Forget it. Study how to install it.

A program may have hundreds of entity classes. modify an existing entity class and add a row to each set? As a programmer, it is impossible to tolerate such operations. Write a tool to read all the entity code, add this line, and save. This is a good solution. Then, each time you add an object class, you have to call the tool to rewrite it. Each time you modify the attribute, you can call it again. No problem. You can use it. This is not what a person who really raises cats can tolerate.

What should we do? Killing a cat? The existence of the toy will be meaningless. Think of a way to create an identical room (inheritance) for all the rooms (entity classes) in the house when I leave the house (Program initialization ), contains copies of all toys that need to be monitored (marked as virtual) in the original room. GPS (-_ ~) is added during the copy process (-_~). Then play with the cat. When a cat enters the inherited room through the door I gave to play with all the toys, GPS will be able to record all the movements of the cat. As soon as I got home, all the toys that the cat had played were known as GPS records. Yo, this little sister-in-law is in Wang yuanxian.
  

You can't understand it. It doesn't matter. Mount the file:
1. During assembly initialization, you can use reflection to find all entity classes inherited from BaseEntity. Traverse the attributes. Find the file marked as virtual for replication.

It took a lot of time to find the virtual attribute at the beginning. I always want to find the property, but I did not expect to go to The set_value method (in fact, the get_value method is also ). It's still amazing.

Note: The NoMapAttribute feature is a custom tag, indicating that the ing is not involved. Monitoring is not required because it is not involved in the ing. It has little to do with the code in this article. For reference only.

// Obtain the Assembly where the object is located (ClassLibraryDemo) var assemblyArray = AppDomain. currentDomain. getAssemblies (). where (w => w. getName (). name = "ClassLibraryDemo "). toList (); // base class var baseEntityType = typeof (BaseEntity) of the object; // loop Assembly foreach (Assembly item in assemblyArray) {// find the object var types = item inherited from the base class in this Assembly. getTypes (). where (t => t. isAbstract = false & baseEntityType. isAssignableFrom (t) & t! = BaseEntityType); foreach (Type btItem in types) {// traverses the attribute var properties = btItem in this object class. getProperties (BindingFlags. public | BindingFlags. instance ). where (w => w. canRead & w. canWrite & w. getCustomAttributes (typeof (NoMapAttribute), false ). any () = false // TODO: Do you want to check the get method? & W. GetSetMethod (). IsVirtual );}}

2. Copy a new room based on the result of 1 (dynamic code generates a class that inherits the object in 1 and overwrites the set Method of the attribute)

This process is designed to generate dynamic code.

// Create a dynamic CodeTypeDeclaration ct = new CodeTypeDeclaration (btItem. name + "_ Dynamic"); // all attributes marked as virtual in the loop object foreach (PropertyInfo fiItem in properties) {// create a property var p = new CodeMemberProperty (); // set the attribute to public and override p. attributes = MemberAttributes. public | MemberAttributes. override; // override // set the property type to the Data Type of the inherited property p. type = new CodeTypeReference (fiItem. propertyType); // The property name is consistent with the inherited p. name = fiItem. name; // contains the set code p. hasSet = true; // contains the get code p. hasGet = true; // set get code // return base. accountp. getStatements. add (new CodeMethodReturnStatement (new CodeFieldReferenceExpression (new CodeBaseReferenceExpression (), fiItem. name); // set the set code // base. account = value; p. setStatements. add (new CodeAssignStatement (new CodeFieldReferenceExpression (new CodeBaseReferenceExpression (), fiItem. name), new CodePropertySetValueReferenceExpression (); // FieldTracking ["Account"] = value; p. setStatements. add (new CodeSnippetExpression ("FieldTracking [\" "+ fiItem. name + "\"] = value "); // Add the attribute to the class ct. members. add (p );}

3. Add the generated class to the namespace where the original class is located + ". Dynamic" (add a suffix to indicate differentiation)

// Declare a Namespace (with the same name and suffix as the current object class) CodeNamespace ns = new CodeNamespace (btItem. Namespace + ". Dynamic"); ns. Types. Add (ct );

4. Edit the Assembly where the generated code is located

// CodeCompileUnit program = new CodeCompileUnit () Assembly for dynamically generating code; // Add reference program. referencedAssemblies. add ("mscorlib. dll "); program. referencedAssemblies. add ("System. dll "); program. referencedAssemblies. add ("System. core. dll "); // define the code factory CSharpCodeProvider provider = new CSharpCodeProvider (); // compile the Assembly var cr = provider. compileAssemblyFromDom (new System. codeDom. compiler. compilerParameters (); // check whether the compilation passes var er Ror = cr. errors; if (error. hasErrors) {Console. writeLine ("error List:"); // compilation fails through foreach (dynamic item in error) {Console. writeLine ("ErrorNumber: {0}; Line: {1}; ErrorText {2}", item. errorNumber, item. line, item. errorText);} return;} else {Console. writeLine ("compiled successfully. ");}

 

View generated code

// View the generated code var codeText = new StringBuilder (); using (var codeWriter = new StringWriter (codeText) {CodeDomProvider. createProvider ("CSharp "). generateCodeFromNamespace (ns, codeWriter, new CodeGeneratorOptions () {BlankLinesBetweenMembers = true});} Console. writeLine (codeText );

 

5. Create a ing relationship between the copied new class and the original class.

Foreach (Type item in ts) {// registration (Simulated Implementation, implemented by dictionary, can also be handled by IOC injection) Mapping. Map (item. BaseType, item );}

6. Obtain the Copied object

// Create a specified object AccountEntity AE = Mapping. GetMap <AccountEntity> ();

7. assign values to attributes of this object

// The primary key assignment does not modify the attribute update AE. baseEntity_Id = 1; // it will not change (not marked as virtual) AE. mainEntity_Name = "Big Cat"; AE. mainEntity_UpdateTime = DateTime. now; // modify an attribute AE. account = "admin"; AE. account = "the last modification prevails ";

8. Call the underlying method. The underlying layer obtains the modified attribute name based on this object attribute.

// Call the methods in the base class to obtain the changed property var up = AE. getFieldTracking (); Console. writeLine ("modified field:"); up. forEach (fe => {Console. writeLine (fe + ":" + AE [fe]);});

9. Perfect

  

 

In this way, the bottom layer will be able to know which entities have been assigned a value.

Of course, if some entities are only used for calculation, you can call a method to delete the Assigned attributes.

// Delete the change field AE. RemoveChanges ("Account ");

 

This is just a simple implementation, and there is a complicated situation. In Step 1, when we obtain the Copied object, how to create and monitor an existing new object. Just like when someone else gave me a ready-made toy room, the cat was playing in it. Hey, let's kill the cat.

 

Summary:

Recognize the power of reflection again.
This is also the first time that code generation and use have been implemented.
I have a deeper understanding of the differences between fields and attributes.
Better understanding of access modifiers and virtual methods.

 

This article is for reference only. It is better if you can solve your problem or learn something by reading this article.

 

The source code has been eaten by the cat, and it has been eaten by the cat ......

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.