Share via


IModelGenerationExtension.OnAfterModelGenerated Method

Defines custom functionality that is executed after an .edmx file has been generated by the Entity Data Model Wizard.

Namespace:  Microsoft.Data.Entity.Design.Extensibility
Assembly:  Microsoft.Data.Entity.Design.Extensibility (in Microsoft.Data.Entity.Design.Extensibility.dll)

Syntax

'Declaration
Sub OnAfterModelGenerated ( _
    context As ModelGenerationExtensionContext _
)
'Usage
Dim instance As IModelGenerationExtension
Dim context As ModelGenerationExtensionContext

instance.OnAfterModelGenerated(context)
void OnAfterModelGenerated(
    ModelGenerationExtensionContext context
)
void OnAfterModelGenerated(
    ModelGenerationExtensionContext^ context
)
function OnAfterModelGenerated(
    context : ModelGenerationExtensionContext
)

Parameters

Remarks

In a Visual Studio extension, the OnAfterModelGenerated method is used to customize the functionality of the Entity Data Model Wizard. Specifically, the OnAfterModelGenerated method modifies an .edmx file after it is generated by the Entity Data Model Wizard.

For more information about extending the functionality of the ADO.NET Entity Data Model Tools, see Extending the Entity Data Model Tools and ADO.NET Entity Data Model Designer Extension Starter Kit.

Examples

In the example below, the ModelGenerationExtension class implements the IModelGenerationExtension interface. By using helper methods, the OnAfterModelGenerated method does the following:

  1. Adds a custom property, MyNewProperty, to each entity type in the conceptual model.

  2. Displays a message box when the model generation process is complete.

Note that the MyNewProperty property will not automatically be visible in the Visual StudioProperties window when an entity type is selected in the Entity Data Model Designer. You can add this functionality by implementing the IEntityDesignerExtendedProperty interface.

[PartCreationPolicy(CreationPolicy.Shared)]
[Export(typeof(IModelGenerationExtension))]
public class ModelGenerationExtension : IModelGenerationExtension
{
    /// <summary>
    /// Called when the selected object in the Entity Data Model Designer changes
    /// and matches the specified EntityDesignerExtendedProperty attribute.
    /// </summary>
    /// <param name="context"></param>
    public void OnAfterModelGenerated(ModelGenerationExtensionContext context)
    {
        //
        // context.CurrentDocument = The XDocument that will be saved. An extension can modify this document. 
        //                           Note that the document may have been modified by another extension's 
        //                           implementation of OnAfterModelGenerated().
        //
        // context.GeneratedDocument = The original XDocument that was generated Entity Data Model Wizard or 
        //                             the Update Model Wizard. An extension cannot modify this document.
        //
        // context.Project = The EnvDTE.Project that contains the .edmx file
        //
        // context.WizardKind = The wizard that initiated the .edmx file generation or update process. 
        //                      Possible values are WizardKind.Generate or WizardKind.UpdateModel.
        //

        bool efv4ModelOrLater = IsEFv4ModelOrLater(context.Project);
        String caption = "OnAfterModelGenerated called";
        String message = String.Format(
            "An EF v{0} model was generated from the database by the '{1}' wizard.\n\n", 
            efv4ModelOrLater ? 4 : 3.5, 
            context.WizardKind == WizardKind.Generate ? "Create Model" : "Update Model From Database");
        if (efv4ModelOrLater)
        {
            // Call helper method to add a new property to the generated EF v2 model.
            AddPropertyToModel(context.CurrentDocument);

            message += "Added a new property to EntityTypes in the generated model.";
        }

        MessageBox.Show(message, caption);
    }

    /// <summary>
    /// Called after a model is updated by the Update Model Wizard.
    /// </summary>
    /// <param name="context"></param>
    public void OnAfterModelUpdated(UpdateModelExtensionContext context)
    {
        //
        // context.OriginalDocument = The original XDocument before the Update Model Wizard started.
        //                            An extension cannot modify this document.
        //
        // context.GeneratedDocument = The XDocument that was generated by the Update Model wizard.
        //                             An extension cannot modify this document.
        //
        // context.UpdateModelDocument = The contents of context.OriginalDocument merged with the 
        // contents of context.GeneratedDocument. An extension cannot modify this document.
        //
        // context.CurrentDocument = The XDocument that will be saved. An extension can modify this 
        // document. Note that the document may have been modified by another extension's implementation 
        // of OnAfterModelGenerated().
        //
        //
        // context.ProjectItem = The EnvDTE.ProjectItem of current .edmx file.
        //
        // context.Project = The EnvDTE.Project that contains the .edmx file.
        //
        // context.WizardKind = The wizard that initiated the .edmx file generation or update process. 
        //                      Possible values are WizardKind.Generate or WizardKind.UpdateModel.
        //

        bool efv4ModelOrLater = IsEFv4ModelOrLater(context.Project);
        String caption = "OnAfterModelGenerated called";
        String message = String.Format(
            "An EF v{0} model was updated from the database by the 'Update Model From Database' wizard.\n\n", 
            efv4ModelOrLater ? 4 : 3.5);

        if (efv4ModelOrLater)
        {
            // Call helper method to add a new property to the generated EF v2 model.
            AddPropertyToModel(context.CurrentDocument);

            message += "Added a new property to EntityTypes in the updated model.";
        }

        MessageBox.Show(message, caption);
    }

    /// <summary>
    /// Returns true if the specified project targets .NET Framework 4 or later; otherwise returns false.
    /// .edmx files in projects that target .NET Framework 4 are EF v4 models. Projects that target 
    /// .NET Framework 3.5 SP1 are EF 3.5 models.
    /// </summary>
    /// <param name="project"></param>
    /// <returns></returns>
    private bool IsEFv4ModelOrLater(Project project)
    {
        bool efv4ModelorLater = false;
        try
        {
            Property targetFrameworkMoniker = project.Properties.Item("TargetFrameworkMoniker");
            System.Runtime.Versioning.FrameworkName frameworkName = new System.Runtime.Versioning.
                FrameworkName(targetFrameworkMoniker.Value.ToString());
            efv4ModelorLater = (frameworkName.Version.Major >= 4);
        }
        catch
        {
            // Nothing to do.
        }
        return efv4ModelorLater;
    }

    /// <summary>
    /// Shows how a model generation extension can annotate the generated model with a new propety
    /// that can be read, displayed and edited by a property extension.
    /// 
    /// Adds a new child XElement to every EntityType element in the generated conceptual model.
    /// The new child XElement is in the same format as properties that are added by a property 
    /// extension.
    /// </summary>
    /// <param name="document">The generated model (EDMX)</param>
    private void AddPropertyToModel(XDocument document)
    {
        bool newPropertyValue = true;

        // Add a new child element, MyNewProperty, as the last child of each EntityType element
        // in the conceptual model. This child element is known as a "Structured Annotation" and 
        // can be accessed with Entity Framework metadata APIs at design time or runtime.
        foreach (XElement entityType in document.Descendants(
            XName.Get("EntityType", "https://schemas.microsoft.com/ado/2008/09/edm")))
        {
            if (entityType.HasElements)
            {
                XElement lastChild = entityType.Elements().Last();
                if (lastChild.Name != MyNewProperty._xnMyNamespace)
                {
                    entityType.Elements().Last().AddAfterSelf(
                        new XElement(MyNewProperty._xnMyNamespace, newPropertyValue.ToString()));
                }
            }
            else
            {
                entityType.Add(new XElement(MyNewProperty._xnMyNamespace, newPropertyValue.ToString()));
            }
        }
    }
}

The following code defines the MyNewProperty class used in the example above.

/// <summary>
/// This class has one public property, MyIntProperty. This property is visible in the Visual Studio
/// Properties window when a conceptual model entity type is selected in the Entity Designer or in 
/// the Model Browser.
/// This property and its value are saved as a structured annotation in an EntityType element in the
/// conceptual content of an .edmx file.
/// </summary>
class MyNewProperty
{
    internal static readonly string _namespace = "http://schemas.tempuri.com/MyNewProperty";
    internal static XName _xnMyNamespace = XName.Get("MyNewProperty", _namespace);
    internal const string _category = "Example Property";

    private XElement _parent;
    private PropertyExtensionContext _context;

    public MyNewProperty(XElement parent, PropertyExtensionContext context)
    {
        _context = context;
        _parent = parent;
    }

    // This property is saved in the conceptual content of an .edmx file in the following format:
    // <EntityType>
    //  <!-- other entity properties -->
    //  <MyNewProperty xmlns:a="http://schemas.tempuri.com/MyNewProperty">true</MyNewProperty>
    // </EntityType>
    [DisplayName("My New Property")]
    [Description("This property is available when a C-Side EntityType is selected in the Entity" + 
        " Designer canvas or the Model Browser. Its values are saved as a structured annotation" + 
        " in the <EntityType> in the EDMX file.")]
    [Category(MyNewProperty._category)]
    [DefaultValue(false)]
    public bool MyBoolProperty
    {
        // Read and return the property value from the structured anotation in the EntityType element.
        get
        {
            bool propertyValue = false;
            if (_parent.HasElements)
            {
                XElement lastChild = _parent.Elements().Last();
                if (lastChild.Name == MyNewProperty._xnMyNamespace)
                {
                    // MyNewProperty element exists, so get its value.
                    bool boolValue = false;
                    if (Boolean.TryParse(lastChild.Value.Trim(), out boolValue))
                    {
                        propertyValue = boolValue;
                    }
                }
            }
            return propertyValue;
        }

        // Write the new property value to the structured anotation in the EntityType element.
        set
        {
            bool propertyValue = value;

            // Make changes to the .edmx file in an EntityDesignerChangeScope to enable undo/redo of changes.
            using (EntityDesignerChangeScope scope = _context.CreateChangeScope("Set MyNewProperty"))
            {
                if (_parent.HasElements)
                {
                    XElement lastChild = _parent.Elements().Last();
                    if (lastChild.Name == MyNewProperty._xnMyNamespace)
                    {
                        // MyNewProperty element already exists under the EntityType element, 
                        // so update its value.
                        lastChild.SetValue(propertyValue.ToString());
                    }
                    else
                    {
                        // MyNewProperty element does not exist, so create a new one as the last child of 
                        // the EntityType element.
                        lastChild.AddAfterSelf(new XElement(_xnMyNamespace, propertyValue.ToString()));
                    }
                }
                else
                {
                    // MyNewProperty element does not exist, so create a new one as the last child of 
                    // the EntityType element.
                    _parent.Add(new XElement(_xnMyNamespace, propertyValue.ToString()));
                }

                // Commit the changes.
                scope.Complete();
            }
        }
    }
}

Permissions

See Also

Reference

IModelGenerationExtension Interface

IModelGenerationExtension Members

Microsoft.Data.Entity.Design.Extensibility Namespace

Other Resources

.edmx File Overview (Entity Framework)

Visual Studio Extensibility Developer Center

Developing Visual Studio Extensions