Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Abonnements

Avoir une propriété sur l'object context qui renvoit les sous-entités

Dans l'entity framework, on a dans l'ObjectContext, une propriété par EntitySet. Le "problème" c'est que si on a une entité Person dérivée par une entité Employee, on n'a qu'un seul EntitySet : Persons.

Pour rajouter une propriété sur notre ObjectContext qui permettent de renvoyer uniquement les Employees, on peut rajouter à notre ObjectContext (partial) une propriété qui utilise la méthode OfType:

public IQueryable<Employee> Employees

{

    get

    {

        return Persons.OfType<Employee>();

    }

}

Jusque là facile.

Comme je l'ai dit sur ce thread du forum msdn hier, il est possible de le faire générer directement par l'outil de génération de code en le customisant.

En partant du code fournit par Elisa, voilà ce que j'ai fait:

public class SampleEdmxCodeGenerator : BaseCodeGeneratorWithSite

{

    private EntityContainer _objectContext;

    private Dictionary<string, EntitySetBase> _entitySetNames;

    private Dictionary<string, List<EntityType>> _typesHierarchyToAddInObjectContext;

    private bool _first = true;

 

    public Dictionary<string, EntitySetBase> EntitySetNames

    {

        get

        {

            if (_entitySetNames == null)

                _entitySetNames = new Dictionary<string, EntitySetBase>();

            return _entitySetNames;

        }

    }

    private Dictionary<string, List<EntityType>> TypesHierarchyToAddInObjectContext

    {

        get

        {

            if (_typesHierarchyToAddInObjectContext == null)

                _typesHierarchyToAddInObjectContext = new Dictionary<string, List<EntityType>>();

            return _typesHierarchyToAddInObjectContext;

        }

    }

    private IEnumerable<EntityType> GetSubEntitiesOf(EntityType baseType)

    {

        var empty = Enumerable.Empty<EntityType>();

        if (_typesHierarchyToAddInObjectContext == null)

            return empty;

        string baseTypeName = baseType.Name;

        if (!_typesHierarchyToAddInObjectContext.ContainsKey(baseTypeName))

            return empty;

        return TypesHierarchyToAddInObjectContext[baseTypeName];

    }

    private void AddSubEntities(EntityType baseType, EntityType typeToAdd)

    {

        string baseTypeName = baseType.Name;

        if (!TypesHierarchyToAddInObjectContext.ContainsKey(baseTypeName))

            TypesHierarchyToAddInObjectContext.Add(baseTypeName, new List<EntityType>());

        TypesHierarchyToAddInObjectContext[baseTypeName].Add(typeToAdd);

    }

 

    protected override string GetDefaultExtension()

    {

        return (".Designer" + base.GetDefaultExtension());

    }

 

    protected override byte[] GenerateCode(string inputFileContent)

    {

        byte[] generatedCodeAsBytes = null;

 

        try

        {

            XElement csdlContent = ExtractCsdlContent(inputFileContent);

            if (csdlContent == null)

            {

                throw new InvalidOperationException("No CSDL content in input file");

            }

 

            _objectContext = null;

            _entitySetNames = null;

            _typesHierarchyToAddInObjectContext = null;

 

            _first = true;

 

            LanguageOption languageOption = LanguageOption.GenerateCSharpCode;

            string fileExtension = base.GetCodeProvider().FileExtension;

            if (fileExtension != null && fileExtension.Length > 0)

            {

                fileExtension = "." + fileExtension.TrimStart(".".ToCharArray());

            }

            if (fileExtension.EndsWith(".vb", StringComparison.InvariantCultureIgnoreCase))

            {

                languageOption = LanguageOption.GenerateVBCode;

            }

            else if (fileExtension.EndsWith(".cs", StringComparison.InvariantCultureIgnoreCase))

            {

                languageOption = LanguageOption.GenerateCSharpCode;

            }

            else

            {

                throw new InvalidOperationException("Unsupported project language. Only C# and VB are supported.");

            }

 

            if (base.CodeGeneratorProgress != null)

            {

                base.CodeGeneratorProgress.Progress(33, 100);

            }

 

            EntityClassGenerator classGenerator;

            IList<EdmSchemaError> errors = null;

            StringWriter codeWriter = new StringWriter(CultureInfo.InvariantCulture);

            for (int i = 0; i < 2; i++)

            {

                using (XmlReader csdlReader = csdlContent.CreateReader())

                {

                    classGenerator = new EntityClassGenerator(languageOption);

                    classGenerator.OnTypeGenerated += new TypeGeneratedEventHandler(OnTypeGenerated);

                    classGenerator.OnPropertyGenerated += new PropertyGeneratedEventHandler(OnPropertyGenerated);

 

                    errors = classGenerator.GenerateCode(csdlReader, codeWriter);

                }

                if (! _first)

                    break;

                _first = false;

                if (base.CodeGeneratorProgress != null)

                {

                    base.CodeGeneratorProgress.Progress(66, 100);

                }

                codeWriter.Dispose();

                codeWriter = new StringWriter(CultureInfo.InvariantCulture);

            }

            if (errors != null)

            {

                foreach (EdmSchemaError error in errors)

                {

                    int line = (error.Line == 0) ? 0 : (error.Line - 1);

                    int column = (error.Column == 0) ? 0 : (error.Column - 1);

 

                    if (error.Severity == EdmSchemaErrorSeverity.Warning)

                    {

                        base.GeneratorWarning(0, error.Message, (uint)line, (uint)column);

                    }

                    else

                    {

                        base.GeneratorError(4, error.Message, (uint)line, (uint)column);

                    }

                }

            }

 

            generatedCodeAsBytes = Encoding.UTF8.GetBytes(codeWriter.ToString());

            codeWriter.Dispose();

            if (base.CodeGeneratorProgress != null)

            {

                base.CodeGeneratorProgress.Progress(100, 100);

            }

        }

        catch (Exception e)

        {

            base.GeneratorError(4, e.Message, 1, 1);

 

            generatedCodeAsBytes = null;

        }

 

        return generatedCodeAsBytes;

    }

 

    private void OnTypeGenerated(object sender, TypeGeneratedEventArgs eventArgs)

    {

        var entityType = eventArgs.TypeSource as System.Data.Metadata.Edm.EntityType;

        if (_first)

        {

            if (entityType != null)

            {

                EdmType baseType;

                if ((baseType = entityType.BaseType) != null)

                {

                    while (baseType.BaseType != null)

                        baseType = baseType.BaseType;

                    var baseEntityType = baseType as EntityType;

                    AddSubEntities(baseEntityType, entityType);

                }

            }

        }

        else

        {

            eventArgs.AdditionalAttributes.AddRange(CreateCodeAttributes(eventArgs.TypeSource));

            var objectContext = eventArgs.TypeSource as EntityContainer;

            if (objectContext != null)

            {

                _objectContext = objectContext;

                var baseEntitySets = _objectContext.MetadataProperties.FirstOrDefault(mp => mp.Name == "BaseEntitySets");

                if (baseEntitySets != null)

                {

                    foreach (var entitySet in (ReadOnlyMetadataCollection<EntitySetBase>)baseEntitySets.Value)

                    {

                        var derivedBaseEntityType = entitySet.ElementType as EntityType;

                        if (derivedBaseEntityType != null)

                        {

                            EntitySetNames.Add(derivedBaseEntityType.Name, entitySet);

                            if (_typesHierarchyToAddInObjectContext != null)

                                foreach (var derivedEntityType in GetSubEntitiesOf(derivedBaseEntityType))

                                {

                                    string derivedEntityTypeName = derivedEntityType.Name;

                                    var newProp = new CodeMemberProperty { Name = derivedEntityTypeName + "s", Attributes = MemberAttributes.Public | MemberAttributes.Final, Type = new CodeTypeReference("global::System.Linq.IQueryable<" + derivedEntityTypeName + ">") };

                                    newProp.GetStatements.Add(new CodeMethodReturnStatement(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), _entitySetNames[derivedBaseEntityType.Name].Name), "OfType", new CodeTypeReference(derivedEntityTypeName)))));

                                    eventArgs.AdditionalMembers.Add(newProp);

                                }

                        }

                    }

                }

            }

        }

    }

 

    private void OnPropertyGenerated(object sender, PropertyGeneratedEventArgs eventArgs)

    {

        if (!_first)

            eventArgs.AdditionalAttributes.AddRange(CreateCodeAttributes(eventArgs.PropertySource));

    }

 

    private IList<CodeAttributeDeclaration> CreateCodeAttributes(MetadataItem item)

    {

        string xmlns = "http://tempuri.org/AttributeAnnotations";

 

        List<CodeAttributeDeclaration> codeAttributeDeclarations = new List<CodeAttributeDeclaration>();

        if (item != null)

        {

            IEnumerable<MetadataProperty> metadataProperties = item.MetadataProperties.Where(prop => prop.Name.StartsWith(xmlns));

            foreach (MetadataProperty metadataProperty in metadataProperties)

            {

                string metadataPropertyValue = (string)metadataProperty.Value;

                if (!String.IsNullOrEmpty(metadataPropertyValue))

                {

                    string[] attributes = metadataPropertyValue.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                    foreach (string attribute in attributes)

                    {

                        string attributeName = attribute;

                        string[] attributeParams = new string[1];

 

                        if (attribute.Contains('('))

                        {

                            attributeParams = attribute.Split(new char[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries);

                            attributeName = attributeParams[0];

                        }

 

                        CodeAttributeDeclaration codeAttributeDeclaration = new CodeAttributeDeclaration(attributeName);

 

                        foreach (string attributeParam in attributeParams.Skip(1))

                        {

                            object attributeParamObj = null;

                            bool attributeParamBool = false;

                            if (bool.TryParse(attributeParam, out attributeParamBool))

                            {

                                attributeParamObj = attributeParamBool;

                            }

                            else

                            {

                                attributeParamObj = attributeParam;

                            }

                            codeAttributeDeclaration.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(attributeParamObj)));

                        }

                        codeAttributeDeclarations.Add(codeAttributeDeclaration);

                    }

                }

            }

        }

        return codeAttributeDeclarations;

    }

 

    private XElement ExtractCsdlContent(string inputFileContent)

    {

        XElement csdlContent = null;

        XNamespace edmxns = "http://schemas.microsoft.com/ado/2007/06/edmx";

        XNamespace edmns = "http://schemas.microsoft.com/ado/2006/04/edm";

 

        XDocument edmxDoc = XDocument.Load(new StringReader(inputFileContent));

        if (edmxDoc != null)

        {

            XElement edmxNode = edmxDoc.Element(edmxns + "Edmx");

            if (edmxNode != null)

            {

                XElement runtimeNode = edmxNode.Element(edmxns + "Runtime");

                if (runtimeNode != null)

                {

                    XElement conceptualModelsNode = runtimeNode.Element(edmxns + "ConceptualModels");

                    if (conceptualModelsNode != null)

                    {

                        csdlContent = conceptualModelsNode.Element(edmns + "Schema");

                    }

                }

            }

        }

        return csdlContent;

    }

}

La grosse différence par rapport à mon précédent générateur custom vient du fait que, le contexte étant généré avant les entity types, je suis obligé ici de faire deux passes de génération. Une pour identifier tous les entity types dérivés et une autre pour réellement générer le code.

Enjoy Big Smile

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Publié jeudi 21 août 2008 13:15 par Matthieu MEZIL

Commentaires

# re: Avoir une propriété sur l'object context qui renvoit les sous-entités @ vendredi 22 août 2008 01:22

Vous trouverez ici une version plus performante.

Matthieu MEZIL

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Les actualités de la semaine sur c2i.fr (14 mai - 20 mai) par Richard Clark le il y a 5 heures et 7 minutes

- Reactive Extensions : Consommer des services avec Rx Partie 3, les pièges à éviter par Léonard Labat le il y a 14 heures et 12 minutes

- SharePoint Blog Site, problème d’archives par Le Blog (Vert) d'Arnaud JUND le 05-20-2012, 13:09

- Soirée ALT.NET Mai - 3 présentations par #Rui le 05-18-2012, 11:59

- [ #SharePoint 2010][ #SQLServer 2012] AlwaysOn pour SharePoint (2/4) : Configuration (2e partie)… par Le blog de Patrick [MVP SharePoint] le 05-18-2012, 11:31

- Team Foundation Server 11: tous les trésors cachés du site d’équipe par Philess le 05-16-2012, 19:01

- [PowerShell 3] Télécharger et installer la documentation en ligne par Blog de SPBrouillet (Pierrick BROUILLET) le 05-16-2012, 17:36

- [#SharePoint 2010][#SQLServer 2012] AlwaysOn pour SharePoint (1/4) : Configuration (1ère partie)… par Le blog de Patrick [MVP SharePoint] le 05-16-2012, 12:10

- Job Day @MIC Brussels - .Net Developers on Mobile applications par Le Blog (Vert) d'Arnaud JUND le 05-15-2012, 20:26

- [SharePoint 2010] – SharePoint 2010, Windows (Server) 8 et des erreurs IIS sont dans une VM… par Blog de SPBrouillet (Pierrick BROUILLET) le 05-14-2012, 12:10