MetadataType哥们类EF产生的POCO - 属性由XmlSerializer的忽略哥们、属性、MetadataType、EF

2023-09-06 11:23:22 作者:甜心大萝卜

我第一次使用EF5数据库。为了序列生成POCO类,我需要使用XMLIgnore属性如下:

I am using EF5 database first. In order to serialize a generated POCO class, I need to use the XMLIgnore attribute as follows

    public partial class Demographics
{
    public string KeyTract { get; set; }
    public string CollectionYear { get; set; }
    public string MSAFIPS { get; set; }
    ...
    ...
    ...
    [XmlIgnore()]
    public virtual ICollection<LoanApp> LoanApps { get; set; }
}

为了保持从加入这个每次我有EF重新创建数据库的模式,我增加了一个哥们类

In order to keep from adding this each time I have EF re-create the model from the database, I added a "buddy class"

    [MetadataType(typeof(Demographic_Metadata))]
public partial class Demographics
{
}

public class Demographic_Metadata
{
    [XmlIgnore()]
    public virtual ICollection<LoanApp> LoanApps { get; set; }
}

但是,当我尝试了人口统计学对象使用XmlSerializer的我得到的序列化有一个错误的反射式......人口统计。

But when I attempt to serialize the Demographics object using XmlSerializer I get "There was an error reflecting type ...Demographics".

在SO研究似乎XMLSerializer的忽略哥们类。但是,有没有人找到了一个解决办法,以避免增加了POCO类是再生每次XMLIgnore属性?

In researching SO it appears that XMLSerializer ignores the buddy class. But has anyone found a workaround to avoid adding the XMLIgnore attribute each time the POCO class is regenerated?

推荐答案

您可以使用,你传入XmlAttributeOverrides XmlSerializer的过载做到这一点。我们需要做的是通过TypeDescriptor填充它,然后作出ICustomAttributeProvider。

You can do this by using the XmlSerializer overload where you pass in the XmlAttributeOverrides. All we need to do is populate it via TypeDescriptor and make an ICustomAttributeProvider.

第一ICustomAttributeProvider是最简单的一种,主要是因为我只是忽略了inhert标志,并总是返回回所有属性。我们的想法是,我们只是传递我们想要的XmlSerializer的了解的属性。

first the ICustomAttributeProvider is the simplest one, mainly because I'm just ignoring the inhert flag and always returning back all the attributes. The idea is that we will just pass in the attributes we want the XmlSerializer to know about.

public class CustomAttributeProvider : ICustomAttributeProvider
{
    private readonly object[] _attributes;

    public CustomAttributeProvider(params Attribute[] attributes)
    {
        _attributes = attributes;
    }

    public CustomAttributeProvider(AttributeCollection attributeCollection)
        : this(attributeCollection.OfType<Attribute>().ToArray())
    {
    }

    public object[] GetCustomAttributes(bool inherit)
    {
        return _attributes;
    }

    public object[] GetCustomAttributes(Type attributeType, bool inherit)
    {
        return _attributes.Where(attributeType.IsInstanceOfType).ToArray();
    }

    public bool IsDefined(Type attributeType, bool inherit)
    {
        return _attributes.Any(attributeType.IsInstanceOfType);
    }
}

现在我要创建一个工厂方法来创建XMLAttributeOverrides。

Now I'm going to create a factory method to create the XMLAttributeOverrides.

我们需要告诉TypeDescriptor关于哥们类,这就是加入AssociatedMetadataTypeTypeDescriptionProvider的供应商名单一样。

We need to tell TypeDescriptor about the buddy class and that's what adding AssociatedMetadataTypeTypeDescriptionProvider to the provider list does.

这是我们使用TypeDescriptor来读取类的属性和特性。由于哥们类不允许领域和TypeDescriptor不读的领域要么,所以我使用反射的领域。

From that we use TypeDescriptor to read the class attributes and the properties. Since buddy classes don't allow fields and TypeDescriptor doesn't read the fields either, so I use reflection for fields.

public static class BuddyClass
{
    public static XmlAttributeOverrides CreateXmlAttributeOverrides(Type type)
    {
        // Tell TypeDescriptor about the buddy class
        TypeDescriptor.AddProvider(new AssociatedMetadataTypeTypeDescriptionProvider(type), type);
        var xmlAttributeOverrides = new XmlAttributeOverrides();
        xmlAttributeOverrides.Add(type, new XmlAttributes(new CustomAttributeProvider(TypeDescriptor.GetAttributes(type))));

        foreach (PropertyDescriptor props in TypeDescriptor.GetProperties(type))
        {
            if (props.Attributes.Count > 0)
            {
             xmlAttributeOverrides.Add(type, props.Name, new XmlAttributes(new CustomAttributeProvider(props.Attributes)));
            }
        }

        foreach (var field in type.GetFields())
        {
            var attributes = field.GetCustomAttributes(true).OfType<Attribute>().ToArray();
            if (attributes.Any())
            {
                xmlAttributeOverrides.Add(type, field.Name, new XmlAttributes(new CustomAttributeProvider(attributes)));
            }
        }

        return xmlAttributeOverrides;
    }
}

您会叫它像

var serializer = new XmlSerializer(typeof(Test), BuddyClass.CreateXmlAttributeOverrides(typeof(Test)));

像通常那样然后用户序列化。这不会对参数和返回值处理的属性。

Then user serializer like you normally would. This doesn't handle the attributes on parameters or return values.