C# 代码优先应用程序中的XML列

C# 代码优先应用程序中的XML列,c#,xml,ef-code-first,entity-framework-migrations,C#,Xml,Ef Code First,Entity Framework Migrations,我试图先在代码中创建一个XML列。我很清楚实体框架并不完全支持XML列,它将它们作为字符串读取。那很好。不过,我仍然希望列类型为XML。这是我的班级: class Content { public int ContentId { get; set; } [Column(TypeName="xml")] public string XmlString { get; set; } [NotMapped] public XElement Xml { get

我试图先在代码中创建一个XML列。我很清楚实体框架并不完全支持XML列,它将它们作为字符串读取。那很好。不过,我仍然希望列类型为XML。这是我的班级:

class Content
{
    public int ContentId { get; set; }

    [Column(TypeName="xml")]
    public string XmlString { get; set; }

    [NotMapped]
    public XElement Xml { get { ... } set { ... } }
 }
问题是,代码优先迁移完全忽略了Column属性,并将字段创建为nvarchar(max)。我试着使用
[DataType(“xml”)]
,但也没用

这是一个迁移错误吗?

您是否尝试过:

public String XmlContent { get; set; }

public XElement XmlValueWrapper
{
    get { return XElement.Parse(XmlContent); }
    set { XmlContent = value.ToString(); }
}

public partial class XmlEntityMap : EntityTypeConfiguration<XmlEntity>
{
    public XmlEntityMap()
    {
        // ...
        this.Property(c => c.XmlContent).HasColumnType("xml");

        this.Ignore(c => c.XmlValueWrapper);
    }
}
公共字符串XmlContent{get;set;}
公共XElement XmlValueWrapper
{
获取{return XElement.Parse(XmlContent);}
设置{XmlContent=value.ToString();}
}
公共部分类XmlEntityMap:EntityTypeConfiguration
{
公共XmlEntityMap()
{
// ...
属性(c=>c.XmlContent).HasColumnType(“xml”);
忽略(c=>c.XmlValueWrapper);
}
}

但是如果XmlContent为空呢

也许:

    public XElement XmlValueWrapper
    {
        get { return XmlContent != null ? XElement.Parse(XmlContent) : null; }
        set { XmlContent = value.ToString(); }
    }

我用一个属性实现了所需的功能,并用该属性装饰了我的模型类xml字段

[XmlType]
public string XmlString { get; set; }

[NotMapped]
public XElement Xml
{
    get { return !string.IsNullOrWhiteSpace(XmlString) ? XElement.Parse(XmlString) : null; }
    set {
        XmlString = value == null ? null : value.ToString(SaveOptions.DisableFormatting);
    }
}
获得以下两篇文章的帮助:

解决方案 定义属性 在上下文中注册属性 在上下文的“OnModelCreating”中

modelBuilder.Conventions.Add(new AttributeToColumnAnnotationConvention<XmlType, string>("XmlType", (p, attributes) => "xml"));
注册自定义Sql生成器 在迁移配置构造函数中,注册自定义SQL生成器

 SetSqlGenerator("System.Data.SqlClient", new CustomSqlGenerator());

现在可以在Entity Framework Core 2.1+中使用SQL Server XML列类型和属性来实现这一点,而不需要额外的属性

公共类内容
{
公共int ContentId{get;set;}
公共XElement Xml{get;set;}
}
内部类ContentEntityTypeConfiguration:IEntityTypeConfiguration
{
公共void配置(EntityTypeBuilder)
{
HasKey(e=>e.ContentId);
builder.Property(e=>e.ContentId)
.ValueGeneratedOnAdd();
属性(e=>e.Xml)
.哈斯转换(
xml=>xml.ToString(),
xml=>xml!=null?XElement.Parse(xml):null
.HasColumnType(“xml”);
}
}
公共类MyDbContext:DbContext
{
公共数据库集内容{get;set;}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
ApplyConfiguration(新ContentEntityTypeConfiguration());
}
}

因为我使用了相同的数据注释,所以我没有尝试这样做。在Fluent API中不存在的数据注释中是否存在错误?我不知道,我只使用过一次带注释的API。Fluent似乎适应性更强,而且对于干净、独立于技术的POCO来说非常好。嗯,它确实有效。我不知道为什么DataAnnotation版本没有。谢谢@我也能得到赏金吗?:)哎呀,我接受了这个答案,我想我受够了。赏金获得。通过“[Column(TypeName=“xml”)]”(注意TypeName),它可以为我生成脚本:“altertable[dbo].[Blogs]ADD[XmlString][xml]”。可能其他一些迁移操作是错误的。是的,对不起,在实际代码中是TypeName。所以没有抓住这个错误。。。我使用的是EF-5,根本没有生成ALTER表。奇怪,现在我很害怕当船长。我的步骤与示例项目()完全相同:a)将DBSet添加到上下文类;b) 按指定添加内容类;c) 在PackageManager控制台中运行“添加迁移”。d) 运行“updatedatabase-Script-Verbose”。我只需要自己将ALTER表添加到生成的迁移代码中。
public class CustomSqlGenerator : SqlServerMigrationSqlGenerator
{
    protected override void Generate(ColumnModel column, IndentedTextWriter writer)
    {
        SetColumnDataType(column);

        base.Generate(column, writer);
    }

    private static void SetColumnDataType(ColumnModel column)
    {
        // xml type
        if (column.Annotations.ContainsKey("XmlType"))
        {
            column.StoreType = "xml";
        }
    }
}
 SetSqlGenerator("System.Data.SqlClient", new CustomSqlGenerator());
public class Content
{
    public int ContentId { get; set; }

    public XElement Xml { get; set; }
}

internal class ContentEntityTypeConfiguration : IEntityTypeConfiguration<Content>
{
    public void Configure(EntityTypeBuilder<Content> builder)
    {
        builder.HasKey(e => e.ContentId);

        builder.Property(e => e.ContentId)
            .ValueGeneratedOnAdd();

        builder.Property(e => e.Xml)
            .HasConversion(
                xml => xml.ToString(),
                xml => xml != null ? XElement.Parse(xml) : null)
            .HasColumnType("xml");
    }
}

public class MyDbContext : DbContext
{
    public DbSet<Content> Contents { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new ContentEntityTypeConfiguration());
    }
}