XML columns in a Code-First application
I achieved what is needed with an attribute and I decorated my model class xml field with the attribute.
[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);
}
}
Got the help of these 2 articles:
https://entityframework.codeplex.com/wikipage?title=Code%20First%20Annotations
https://andy.mehalick.com/2014/02/06/ef6-adding-a-created-datetime-column-automatically-with-code-first-migrations/
Solution
Define Attribute
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class XmlType : Attribute
{
}
Register Attribute in Context
In the "OnModelCreating" of the context
modelBuilder.Conventions.Add(new AttributeToColumnAnnotationConvention<XmlType, string>("XmlType", (p, attributes) => "xml"));
Custom Sql Generator
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";
}
}
}
Register Custom Sql Generator
In the Migration Configuration constructor, register the custom SQL generator.
SetSqlGenerator("System.Data.SqlClient", new CustomSqlGenerator());
Have you tried:
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);
}
}
This can now be achieved, without the need for an additional property, in Entity Framework Core 2.1+, using a SQL Server XML column type and value conversions.
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());
}
}