ExtendedXmlSerializer / home

A configurable and eXtensible Xml serializer for .NET.
https://extendedxmlserializer.github.io/
MIT License
336 stars 47 forks source link

Database members #212

Closed ferzisdis closed 6 years ago

ferzisdis commented 6 years ago

Hi! I want to serialize types that contain objects from a database. Serializing the following line using IConverted: public string Format(DatabaseObject instance) { return instance.IdTable + "@" + instance.Guid; }

In the process of deserialization, I want to perform a Sql-request to the database in order to get the DatabaseObject.

The problem is that in this way I will send a lot of single requests to the database. I need a deferred method for setting the value. Like that:

public void Parse(string data) { //this.MemberValue - is a member, who I want set   mementoContext.AddEpdToLoad (data, loadedObj => this.MemberValue = (DatabaseObject) loadedObj); }

Can I solve my problem using standard ExtendedXmlSerializer methods?

Mike-E-angelo commented 6 years ago

Hey @ferzisdis thanks for writing in. This is a compelling scenario and think I have a solution for you. Check it out: https://github.com/wojtpl2/ExtendedXmlSerializer/blob/865e58d0991cc4db982261e8bc950bc8ce002cc2/test/ExtendedXmlSerializer.Tests/ReportedIssues/Issue212Tests.cs#L27-L47

This makes use of a registered serializer to do the work for you. It also makes use of a proxy class to persist the necessary data and then use it to read back in.

The only downside is that in order to do this, some classes had to be exposed as public. To successfully use this you will have to use the latest version from our preview feed here:

https://www.myget.org/F/wojtpl2/api/v3/index.json

Please give this a try and if you have any issues/questions/problems please let me know and I will do my best to assist.

ferzisdis commented 6 years ago

Hey @Mike-EEE, Thanks for answer, Your option is amazing!!!

I adapted to myself, implemented a more versatile way. For processing all DatabaseObject members.

I create Method "SetValue" in class "Serializer". But this is not a very beautiful decision. How can I set a property to an object using standard methods of your library?


        static void Main(string[] args)
        {

            var serializer = new ConfigurationContainer().EnableReaderContext()
                .ConfigureType<DatabaseObject>().Register(typeof(Serializer))
                .Create();

            var instance = new Wellbore()
            {
                Well = new DatabaseObject(){ Id = Guid.NewGuid(), Table = "Well", Creted = "Hand"},
                Kind = new DatabaseObject(){ Id = Guid.NewGuid(), Table = "Kind", Creted = "Hand"}
            };

            var content = serializer.Serialize(instance);

            var key = new XmlReaderFactory().Get(new MemoryStream(Encoding.UTF8.GetBytes(content)));

            var deserialize = serializer.Deserialize(key);
            Proxies.Default.RestoreDatabaseObjects(key);

        }

        interface IProxies : IParameterizedSource<object, IList<ValueTuple<Proxy,Action<DatabaseObject>>>>
        {
        }

        sealed class Proxies : ReferenceCache<object, IList<ValueTuple<Proxy,Action<DatabaseObject>>>>, IProxies
        {
            public static Proxies Default { get; } = new Proxies();

            public Proxies() : base(_ => new List<(Proxy, Action<DatabaseObject>)>())
            {

            }

            public void RestoreDatabaseObjects(XmlReader key)
            {
                var list = this.Get(key);

                //Do processing/database calls here. 
                foreach (var valueTuple in list)
                {
                    valueTuple.Item2.Invoke(new DatabaseObject(){ Id = valueTuple.Item1.Id, Table = valueTuple.Item1.Table, Creted = "Loader"});
                }
            }
        }

        sealed class Serializer : ISerializer<DatabaseObject>
        {
            private readonly ISerializer serializer;
            private readonly IContentsHistory hystory;
            private readonly IProxies proxies;

            public Serializer(IContents contents) : this(contents.Get(typeof(Proxy).GetTypeInfo()),
                ContentsHistory.Default, Proxies.Default)
            {

            }
            public Serializer(ISerializer serializer, IContentsHistory hystory, IProxies proxies)
            {
                this.serializer = serializer;
                this.hystory = hystory;
                this.proxies = proxies;
            }

            public DatabaseObject Get(IFormatReader parameter)
            {
                var owner = hystory.Get(parameter).Peek().Current;
                var proxy = (Proxy) serializer.Get(parameter);

                var parameterName = parameter.Name;
                proxies.Get(parameter.Get()).Add((proxy, new Action<DatabaseObject>(e =>
                {
                    this.SetValue(parameterName, owner, e);
                })));

                return null;
            }

            public void SetValue(string parametrName, object owner, object value)
            {
                var propertyInfo = owner.GetType().GetProperty(parametrName);
                if (propertyInfo != null)
                {
                    propertyInfo.SetValue(owner, value);
                    return;
                }
                throw new Exception("Don't support!");
            }

            public void Write(IFormatWriter writer, DatabaseObject instance)
            {
                serializer.Write(writer, new Proxy(){ Id = instance.Id, Table =  instance.Table});
            }
        }
Mike-E-angelo commented 6 years ago

Cool! I am surprised any of this works, @ferzisdis. 😆 You do bring up a good point... if you want to have a general way to access/set members we already have components that do that. I have exposed these as well. Check it out:

https://github.com/wojtpl2/ExtendedXmlSerializer/blob/baf57e0d14dcd7f2035e3618cea26a3b8dbd5373/test/ExtendedXmlSerializer.Tests/ReportedIssues/Issue212Tests.cs#L57-L128

Please let me know if you run into any problems with it. Please also note that you might have to clear out your c:\users\.nuget\packages\ExtendedXmlSerializer folder to get the latest preview due to issue #184.

ferzisdis commented 6 years ago

Thanks for help, @Mike-EEE :3 , This is work perfect! I really liked the architecture of your project.

Mike-E-angelo commented 6 years ago

Great! Glad to hear, @ferzisdis. And thank you for the kind words. That's why I do this. 😇

Mike-E-angelo commented 6 years ago

Alrighty, the code used here has been deployed to our public nuget feed as v2.1.13. Please let us know if you encounter any further issues and we will check it out. Closing for now.