public abstract void Process(EfProcessorContext ctx, EfPropertyDefinition definition);
 public abstract void Process(EfProcessorContext ctx, IReadOnlyCollection <EfPropertyDefinition> properties);
예제 #3
0
        public static ModelBuilder BuildCustomAttributes(this ModelBuilder model, IEfCustomContext dbContext)
        {
            var entityTypes     = model.Model.GetEntityTypes();
            var modelChangeLock = new object();

            Parallel.ForEach(entityTypes, entityType =>
            {
                // matches, ctx and the tally are lazily loaded to avoid computing when no actual matching attributes
                // exist.
                MultiValueDictionary <EfIndirectProcessorBaseAttribute, EfPropertyDefinition> matches = null;
                EfProcessorContext ctx           = null;
                ISet <Type> uniqueAttributeTally = null;

                foreach (var prop in entityType.ClrType.GetProperties())
                {
                    //TODO does this actually include types inheriting that type?
                    var attrs = Attribute.GetCustomAttributes(prop, typeof(EfPropertyBaseAttribute));

                    // note to self: we don't restart the tally for every new property, that ruins the entire point, we
                    // have AttributeUsage.AllowMultiple for that

                    foreach (var attr in attrs)
                    {
                        // lazily initialize the context (so we don't do model.Entity when we don't need to)
                        if (ctx == null)
                        {
                            ctx = new EfProcessorContext
                            {
                                Model           = model,
                                Entity          = model.Entity(entityType.ClrType),
                                EntityType      = entityType,
                                DatabaseContext = dbContext,
                            };
                        }

                        // this is better kept local
                        var definition = new EfPropertyDefinition
                        {
                            Property = prop,
                            Source   = attr,
                        };

                        // we need the EfPropertyBaseAttribute value, but we can't do that inside the switch block, so
                        // we're using pattern matching here
                        if (!(attr is EfPropertyBaseAttribute baseAttr))
                        {
                            continue;
                        }

                        if (!baseAttr.CanHaveMultiple)
                        {
                            if (uniqueAttributeTally == null)
                            {
                                // lazily initialize the tally
                                // if there is no tally, there is no need to check if it contains the type
                                uniqueAttributeTally = new HashSet <Type> {
                                    baseAttr.GetType()
                                };
                            }
                            else if (!uniqueAttributeTally.Add(baseAttr.GetType()))
                            {
                                throw new EfAttributeException(
                                    $"The property {prop} contains multiple instances of {baseAttr.GetType()}");
                            }
                        }

                        switch (attr)
                        {
                        case EfPropertyProcessorBaseAttribute processor:
                            lock (modelChangeLock)
                            {
                                processor.Process(ctx, definition);
                            }
                            break;

                        case EfIndirectProcessorBaseAttribute indirectProcessor:
                            if (indirectProcessor.PropertyMatches(ctx, definition))
                            {
                                if (matches == null)
                                {
                                    matches = new MultiValueDictionary <EfIndirectProcessorBaseAttribute, EfPropertyDefinition>();
                                }
                                matches.Add(indirectProcessor, definition);
                            }
                            break;
                        }
                    }
 public abstract bool PropertyMatches(EfProcessorContext ctx, EfPropertyDefinition definition);