EntityFramework 6.0.0-alpha3 - EdmxWriter.WriteEdmx() 在从 alpha2 更新到 alpha3 后失败

Posted

技术标签:

【中文标题】EntityFramework 6.0.0-alpha3 - EdmxWriter.WriteEdmx() 在从 alpha2 更新到 alpha3 后失败【英文标题】:EntityFramework 6.0.0-alpha3 - EdmxWriter.WriteEdmx() fails after update to alpha3 from alpha2 【发布时间】:2013-03-04 09:59:46 【问题描述】:

以下扩展适用于 EF6 alpha2,但因空引用异常而停止使用 alpha3。失败的语句是 EdmxWriter.WriteEdmx(..)

视图预生成是在代码优先的上下文中执行的。

如何使用 EF6 alpha3 实现预生成视图?

 public static PreGeneratedViews PreGenerateViews<T>(this T dbContext) where T : DbContext
    
        Trace.TraceInformation("PreGenerating views");

        //define ef collections
        EdmItemCollection edmItemCollection = null;
        StoreItemCollection storeItemCollection = null;
        StorageMappingItemCollection mappingItemCollection = null;

        //get ef collections
        GetItemCollections(
            GetEdmx(dbContext),
            out edmItemCollection,
            out storeItemCollection,
            out mappingItemCollection);

        IList<EdmSchemaError> errors = null;
        //get the generated views
        Dictionary<string, string> extentViews = GetExtentViews(mappingItemCollection, out errors);


        //return the pregenerated views as string (xml document)
        return new PreGeneratedViews
                   
                       EdmEntityContainerName = edmItemCollection.GetItems<EntityContainer>().Single().Name,
                       StoreEntityContainerName = storeItemCollection.GetItems<EntityContainer>().Single().Name,
                       HashOverMappingClosure =
                           ReflectionHelper.GetMappingClosureHash(edmItemCollection.EdmVersion,
                                                                  mappingItemCollection),
                       HashOverAllExtentViews =
                           ReflectionHelper.GenerateHashForAllExtentViewsContent(edmItemCollection.EdmVersion,
                                                                                 extentViews),
                       ViewCount = extentViews.Count,
                       Views = CreateViews(extentViews),
                       ViewsEmbeddedResourceName =
                           string.Format("DbContextViews0.xml", Guid.NewGuid().ToString("N")),
                   ;
    

    private static XDocument GetEdmx(DbContext dbContext)
    
        var ms = new MemoryStream();

        using (XmlWriter writer = XmlWriter.Create(ms))
        
            EdmxWriter.WriteEdmx(dbContext, writer);
        

        ms.Position = 0;

        return XDocument.Load(ms);
    

    private static void SplitEdmx(XDocument edmx, out XmlReader csdlReader, out XmlReader ssdlReader,
                                  out XmlReader mslReader)
    
        // xml namespace agnostic to make it work with any version of Entity Framework
        XNamespace edmxNs = edmx.Root.Name.Namespace;

        XElement storageModels = edmx.Descendants(edmxNs + "StorageModels").Single();
        XElement conceptualModels = edmx.Descendants(edmxNs + "ConceptualModels").Single();
        XElement mappings = edmx.Descendants(edmxNs + "Mappings").Single();

        ssdlReader = storageModels.Elements().Single(e => e.Name.LocalName == "Schema").CreateReader();
        csdlReader = conceptualModels.Elements().Single(e => e.Name.LocalName == "Schema").CreateReader();
        mslReader = mappings.Elements().Single(e => e.Name.LocalName == "Mapping").CreateReader();
    

    private static void GetItemCollections(XDocument edmx, out EdmItemCollection edmItemCollection,
                                           out StoreItemCollection storeItemCollection,
                                           out StorageMappingItemCollection mappingItemCollection)
    
        // extract csdl, ssdl and msl artifacts from the Edmx
        XmlReader csdlReader, ssdlReader, mslReader;
        SplitEdmx(edmx, out csdlReader, out ssdlReader, out mslReader);

        // Initialize item collections
        edmItemCollection = new EdmItemCollection(new[] csdlReader);
        storeItemCollection = new StoreItemCollection(new[] ssdlReader);
        mappingItemCollection = new StorageMappingItemCollection(edmItemCollection, storeItemCollection,
                                                                 new[] mslReader);
    

    private static Dictionary<string, string> GetExtentViews(StorageMappingItemCollection mappingItemCollection,
                                                             out IList<EdmSchemaError> errors)
    
        Dictionary<EntitySetBase, string> views = ReflectionHelper.GenerateViews(mappingItemCollection, out errors);
        if (errors != null && errors.Any())
        
            return null;
        

        var extentViews = new Dictionary<string, string>(views.Count);

        foreach (var kvp in views)
        
            extentViews.Add(
                GetExtentFullName(kvp.Key),
                kvp.Value.Replace("\r\n", "\n")); // replace accounts for Xml new line normalization
        

        return extentViews;
    

    private static string GetExtentFullName(EntitySetBase entitySet)
    
        return string.Format("0.1", entitySet.EntityContainer.Name, entitySet.Name);
    


    private static string CreateViews(Dictionary<string, string> extentViews)
    
        var sb = new StringBuilder();
        //var embeddedViewsFileName = Path.ChangeExtension(Host.TemplateFile, "xml");
        using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings
                                                           
                                                               Indent = true,
                                                               Encoding = Encoding.UTF8
                                                           ))
        
            writer.WriteStartElement("views");
            foreach (var kvp in extentViews)
            
                writer.WriteStartElement("view");
                writer.WriteAttributeString("extent", kvp.Key);
                writer.WriteCData(kvp.Value);
                writer.WriteEndElement();
            

            writer.WriteEndElement();
        

        return sb.ToString();
    

    #region Nested type: ReflectionHelper

    private static class ReflectionHelper
    
        private static readonly Assembly efAssembly = typeof (StorageMappingItemCollection).Assembly;

        private static readonly MethodInfo generateViewsMethodInfo =
            typeof (StorageMappingItemCollection).GetMethod("GenerateEntitySetViews",
                                                            BindingFlags.NonPublic | BindingFlags.Instance);

        private static readonly MethodInfo getMappingClosureHashMethodInfo =
            efAssembly.GetType("System.Data.Entity.Core.Mapping.MetadataMappingHasherVisitor", true)
                .GetMethod("GetMappingClosureHash", BindingFlags.Static | BindingFlags.NonPublic);

        private static readonly MethodInfo generateHashForAllExtentViewsContentMethodInfo =
            efAssembly.GetType("System.Data.Entity.Core.Common.Utils.MetadataHelper", true)
                .GetMethod("GenerateHashForAllExtentViewsContent", BindingFlags.Static | BindingFlags.NonPublic);

        public static Dictionary<EntitySetBase, string> GenerateViews(
            StorageMappingItemCollection mappingItemCollection, out IList<EdmSchemaError> errors)
        
            errors = null;
            return
                (Dictionary<EntitySetBase, string>)
                generateViewsMethodInfo.Invoke(mappingItemCollection, new object[] errors);
        

        public static string GetMappingClosureHash(double schemaVersion,
                                                   StorageMappingItemCollection mappingItemCollection)
        
            return (string) getMappingClosureHashMethodInfo.Invoke(
                null,
                new object[]
                    
                        schemaVersion, 
                        // CodeFirst currently creates always one entity container
                        mappingItemCollection.GetItems<GlobalItem>().Single(
                            i => i.GetType().Name == "StorageEntityContainerMapping")
                    );
        

        public static string GenerateHashForAllExtentViewsContent(double schemaVersion,
                                                                  Dictionary<string, string> extentViews)
        
            return (string) generateHashForAllExtentViewsContentMethodInfo.Invoke(
                null,
                new object[] schemaVersion, extentViews);
        
    

堆栈跟踪如下:

NullReferenceException

在:System.Data.Entity.Edm.Serialization.EdmSerializationVisitor.VisitEdmAssociationSet(AssociationSet 项) 在:System.Data.Entity.Edm.EdmModelVisitor.VisitCollection[T](IEnumerable1 collection, Action1 visitMethod) 在:System.Data.Entity.Edm.EdmModelVisitor.VisitAssociationSets(EntityContainer 容器,IEnumerable`1 关联集) 在:System.Data.Entity.Edm.EdmModelVisitor.VisitEdmEntityContainer(EntityContainer item) 在:System.Data.Entity.Edm.Serialization.EdmSerializationVisitor.VisitEdmEntityContainer(EntityContainer item) 在:System.Data.Entity.Edm.EdmModelVisitor.VisitCollection[T](IEnumerable1 collection, Action1 visitMethod) 在:System.Data.Entity.Edm.EdmModelVisitor.VisitEntityContainers(IEnumerable`1 entityContainers) 在:System.Data.Entity.Edm.EdmModelVisitor.VisitEdmModel(EdmModel 项目) 在:System.Data.Entity.Edm.Serialization.EdmSerializationVisitor.Visit(EdmModel edmModel, String namespaceName, String provider, String providerManifestToken) 在:System.Data.Entity.Edm.Serialization.EdmSerializationVisitor.Visit(EdmModel edmModel, String provider, String providerManifestToken) 在:System.Data.Entity.Edm.Serialization.SsdlSerializer.Serialize(EdmModel dbDatabase, String provider, String providerManifestToken, XmlWriter xmlWriter, Boolean serializeDefaultNullability) 在:System.Data.Entity.ModelConfiguration.Edm.Serialization.EdmxSerializer.WriteEdmxRuntime() 在:System.Data.Entity.ModelConfiguration.Edm.Serialization.EdmxSerializer.Serialize(DbDatabaseMapping databaseMapping, DbProviderInfo providerInfo, XmlWriter xmlWriter) 在:System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbModel 模型,XmlWriter 编写器) 在:System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext 上下文,XmlWriter 编写器) 在:**.DbContextPreGenerateViewExtension.GetEdmx(DbContext dbContext)

谢谢!

【问题讨论】:

最好将此问题报告为EF's codeplex site 上的错误。 供参考:一个新的issue已经提交到codeplex 我认为这只发生在某些模型上 - 你能展示你的模型吗? 该模型是基于代码的模型,我目前实际上无法发布。但一般来说,它使用标准实体建模和基于表属性的每个具体类型层次结构映射的表......不幸的是,这种方法似乎存在一个已知错误......(参考在这里inheritance mapping) 【参考方案1】:

我刚刚提交了对工作项 867 (35852e8392ad) 的修复。它应该修复 NRE。该修复程序应包含在今天的夜间构建中。你可以试一试,让我知道这是否解决了问题?

【讨论】:

【参考方案2】:

这是 Alpha 3 中已知的 bug。

【讨论】:

在引用的问题中,我正在使用基于 [Table] 属性的继承映射...在 EF6 最终版本中有修复的机会,还是应该在我的模型中寻找解决方法?谢谢。 这将在下一个版本中修复。

以上是关于EntityFramework 6.0.0-alpha3 - EdmxWriter.WriteEdmx() 在从 alpha2 更新到 alpha3 后失败的主要内容,如果未能解决你的问题,请参考以下文章

EntityFramework优缺点

EntityFramework 7 更名为EntityFramework Core(预发布状态)

EntityFramework codefirst

解决适用EntityFramework生成时报错“无法解析依赖项。"EntityFramework 6.4.4" 与 ' EntityFramework.zh-Hans 6

EntityFramework 开始小试

EntityFramework Code First 添加唯一键