/// <summary> /// 构造一个代理对象。 /// </summary> /// <returns></returns> public static TEntity New() { return((TEntity)EntityCompiler.NewProxy(typeof(TEntity))); }
// <summary> // Processes the given context type to determine the DbSet or IDbSet // properties and collect root entity types from those properties. Also, delegates are // created to initialize any of these properties that have public setters. // If the type has been processed previously in the app domain, then all this information // is returned from a cache. // </summary> // <returns> A dictionary of potential entity type to the list of the names of the properties that used the type. </returns> private Dictionary <Type, List <string> > GetSets() { EntityContextTypesInitializersPair setsInfo; var contextType = _context.GetType(); if (!_objectSetInitializers.TryGetValue(contextType, out setsInfo)) { // It is possible that multiple threads will enter this code and create the list // and the delegates. However, the result will always be the same so we may, in // the rare cases in which this happens, do some work twice, but functionally the // outcome will be correct. var dbContextParam = Expression.Parameter(typeof(EntityContext), "dbContext"); var initDelegates = new List <Action <EntityContext> >(); var typeMap = new Dictionary <Type, List <string> >(); // Properties declared directly on DbContext such as Database are skipped foreach (var propertyInfo in contextType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.GetIndexParameters().Length == 0 && p.DeclaringType != typeof(EntityContext))) { var entityType = GetSetType(propertyInfo.PropertyType); if (entityType != null) { // We validate immediately because a DbSet/IDbSet must be of // a valid entity type since otherwise you could never use an instance. if (!entityType.IsValidStructuralType()) { //throw Error.InvalidEntityType(entityType); } List <string> properties; if (!typeMap.TryGetValue(entityType, out properties)) { properties = new List <string>(); typeMap[entityType] = properties; } properties.Add(propertyInfo.Name); var setter = propertyInfo.GetSetMethod(); if (setter != null && setter.IsPublic) { var setMethod = SetMethod.MakeGenericMethod(entityType); var newExpression = Expression.Call(dbContextParam, setMethod); var setExpression = Expression.Call( Expression.Convert(dbContextParam, contextType), setter, newExpression); initDelegates.Add( Expression.Lambda <Action <EntityContext> >(setExpression, dbContextParam).Compile()); } } } Action <EntityContext> initializer = dbContext => { foreach (var initer in initDelegates) { initer(dbContext); } }; setsInfo = new EntityContextTypesInitializersPair(typeMap, initializer); EntityCompiler.CompileContextTypes(contextType, typeMap.Keys.ToArray()); // If TryAdd fails it just means some other thread got here first, which is okay // since the end result is the same info anyway. _objectSetInitializers.TryAdd(_context.GetType(), setsInfo); } return(setsInfo.EntityTypeToPropertyNameMap); }