views:

442

answers:

2

I just cannot get this to work, would appreciate if someone can help.

So I get back an XML result from a database which looks like:

<matches>
  <issuer client_name="MTR" score="6" match_list="MTR CORPORATION LIMITED"/>
  <issuer client_name="PEOPLE''S REPUBLIC OF CHINA" score="4"
          match_list="DEMOCRATIC PEOPLE'S REPUBLIC OF KOREA;GOVERNMENT OF THE
          HONG KONG SPECIAL ADMINISTRATIVE REGION OF THE PEOPLE'S REPUBLIC OF
          CHINA;MONGOLIAN PEOPLE'S REPUBLIC;PEOPLE'S DEMOCRATIC REPUBLIC OF
          ALGERIA;PEOPLE'S REPUBLIC OF CHINA"/>
</matches>

From this XML I need to populate an object after doing some logic like matching the client_name I am getting back in the XML result to the one I have sent to database to get matches.

       XDocument.Load(new StringReader(
                              row.GetString(row.GetOrdinal("xml_ret"))))))
                 .Single().Descendants("matches")
                 .Select(x =>
                     new Pool() {
                         Constituents = (IEnumerable<Constituent>)
                            //(... cannot work this how can IsReference populate)
                         //ClientName = x.Attribute("client_name").Value,
                         //Score = x.Attribute("score").Value,
                         //MatchList = x.Attribute("match_list").Value,
                     });

In a non-LINQ manner I can populate the object something like this:

foreach (Constituent constituent in pool.Constituents)
        {
            if (!string.IsNullOrEmpty(constituent.Name)
                && string.IsNullOrEmpty(constituent.Curve))
            {
                i++;

                ConstituentMatch match = new ConstituentMatch();
                ConstituentMatch.Group group =new ConstituentMatch.Group("High");

                //High Match group
                ICollection<string> curves = new List<string>();
                curves.Add("EUR" + i);
                curves.Add("USD" + i);

                ICollection<string> names = new List<string>();

                ConstituentMatch.Group.Entry entry =
                    new ConstituentMatch.Group.Entry(constituent.Name + " Ltd.",
                                                     curves);
                group.Add(entry);
                entry =
                    new ConstituentMatch.Group.Entry(constituent.Name + " Inc.",
                                                     curves);
                group.Add(entry);

                match.AddGroup(group);

            }
        }

But how can I do this using LINQ, as I am sure you can do it, I just cannot work it out.

The constituent class looks like:

public sealed class Constituent
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public ConstituentMatch Match {get;set;}

    public Constituent(string name)
    {
        this.name = name;
    }

    public Constituent() : this(string.Empty) { }
}

And constituent match class looks like this:

public sealed class ConstituentMatch
{
    private readonly Dictionary<string, Group> matches = new Dictionary<string, Group>();

    public IEnumerable<string> GroupNames
    {
        get { return matches.Keys; }
    }

    public Group this[string name]
    {
        get { return matches[name]; }
    }

    public IEnumerable<Group> Groups
    {
        get { return matches.Values; }
    }

    public void AddGroup(Group group)
    {
        matches[group.Name] = group;
    }

    /// <summary>
    /// Match group e.g. Poor, High, All, Begins With
    /// </summary>
    public sealed class Group
    {
        private readonly string name;
        private readonly ICollection<Entry> matches = new List<Entry>();

        public string Name
        {
            get { return name; }
        }

        public Group(string name)
        {
            this.name = name;
        }

        public void Add(Entry entry)
        {
            matches.Add(entry);
        }

        public override bool Equals(object obj)
        {
            bool result = false;
            if (obj is Group)
            {
                Group other = obj as Group;
                result = name == other.name;
            }
            return result;
        }

        public override int GetHashCode()
        {
            return name.GetHashCode();
        }

        public sealed class Entry
        {
            private string legalName;
            private IEnumerable<string> curves;

            private double notional     = double.NaN;
            private char seniriority    = 'N';

            public string LegalName
            {
                get { return legalName; }
            }

            public IEnumerable<string> Curves
            {
                get { return curves; }
            }

            public Entry(string legalName, IEnumerable<string> curves)
                       : this(legalName, curves, double.NaN, 'N') { }

            public Entry(string legalName,
                         IEnumerable<string> curves,
                         double notional,
                         char seniriority)
            {
                this.legalName = legalName;
                this.curves = curves;
                this.notional = notional;
                this.seniriority = seniriority;
            }
        }
    }
}
+1  A: 

Language INtegrated Query is, as its name says, a technology for querying objects and data, not for modifying them.

Justice
Linq can be used to create sequences of objects, which seems to be what was asked.
Martinho Fernandes
Everytime you see a `foreach` in code, there's a high probability it can be rewritten with Linq.
Martinho Fernandes
Yes agree, but my question is how inside select expression i can poulate my IEnumerable object like i can do using non-lambda approach. Any help would be appreciated.I have also attached snippet as how i can populate my desired object in non-lambda way.
netmatrix01
thanks Martinho, I am exactly after that. Glad you can understand my question. Any help would be appreciated.
netmatrix01
There's a long way between "can" and "should." There is no LINQ statement that would be either clearer, faster, or more flexible than that foreach.
mquander
+1  A: 

Some thing similar to this should work

var haystack = new Pool().Constituents;
var indexedhaystack = haystack.Select((item, index)=> new {
    item, index
});
var pool = new Pool()
{
    Constituents = from l in indexedhaystack
                   select new Constituent()
                   {
                        //your stuff here
                   }
};

... extended ...

var constituents = new Pool().Constituents.Select((c, i) =>
    new
    {
        Constituent = c,
        Index = i
    });
var items = from c in constituents
            where !string.IsNullOrEmpty(c.Constituent.Name)
                  && string.IsNullOrEmpty(c.Constituent.Curve)
            let curves = new[]{
                            "EUR" + c.Index.ToString(),
                            "USD" + c.Index.ToString()
                               }
            let match = new ConstituentMatch(){
                new Group("High") {
                    new Entry(
                                c.Constituent.Name + " Ltd.",
                                curves),
                    new Entry(
                                c.Constituent.Name + " Inc.",
                                curves)
                }
            }
            select new
            {
                Name = c.Constituent.Name,
                Curves = curves,
                Match = match
            };

...

public class Constituent
{
    public string Name { get; set; }
    public string Curve { get; set; }
}
public class Pool
{
    public List<Constituent> Constituents { get; set; }
}
public class Entry
{
    public Entry(string entry, IEnumerable<string> curves)
    {
    }
}
public class Group : List<Entry>
{
    public Group(string group) { }
}
public class ConstituentMatch : List<Group>
{

}
Matthew Whited
Hello Matthew,Many thanks for your brilliant and long effort, actually my question was how can i populate object Constituents = (IEnumerable<Constituent>) //(... cannot work this how can IsReference populate) inside the select query while querying my xdocument. You have actually converted my dummy object implementation to linq which is brilliant as well as i get to learn how i can do that. But is there any chance you can be of help in explaining me how can i populate the IEnumarebale<Constituent> inside my select query. Thanks , AG
netmatrix01
Just make the Constituents property equal to anything that is of the type. you can just put a linq query right on line line. Bye the way if you can I would move your classed to a namespace instead of having them be nested classes. Might be much easier to read and maintain.
Matthew Whited