Linq Many to Many relationship and XML

  • Thread starter Thread starter shapper
  • Start date Start date
S

shapper

Hello,

I am trying to create a Many to Many relationship using XML files:

<As>
<A>
<Id>1</Id>
</A>
<A>
<Id>2</Id>
</A>
<As>

<ABs>
<AB>
<AId>1</AId>
<BId>1</BId>
</AB>
<AB>
<AId>2</AId>
<BId>1</BId>
</AB>
<ABs>

<Bs>
<B>
<Id>1</Id>
</B>
<B>
<Id>2</Id>
</B>
<Bs>

And my objects are simply:

public class A {
public Int32 Id { get; set; }
public IList<B> Bs { get; set; }
}

public class B {
public Int32 Id { get; set; }
}

Basically, I need to create a List of objects A and for each fill the
Bs in each A.

return _As.Root.Elements("A").Select(u => new A {
Id = Int32.Parse(u.Element("Id").Value),
Bs = _ABs.Root.Elements("AB"). //?????
}).AsList();

Where _As, _ABs and _Bs are XDocuments loaded from the 3 XML files.

How can I fill Bs for each A?

Thanks,
Miguel
 
shapper said:
I am trying to create a Many to Many relationship using XML files:

<As>
<A>
<Id>1</Id>
</A>
<A>
<Id>2</Id>
</A>
<As>

<ABs>
<AB>
<AId>1</AId>
<BId>1</BId>
</AB>
<AB>
<AId>2</AId>
<BId>1</BId>
</AB>
<ABs>

<Bs>
<B>
<Id>1</Id>
</B>
<B>
<Id>2</Id>
</B>
<Bs>

And my objects are simply:

public class A {
public Int32 Id { get; set; }
public IList<B> Bs { get; set; }
}

public class B {
public Int32 Id { get; set; }
}

Basically, I need to create a List of objects A and for each fill the
Bs in each A.

return _As.Root.Elements("A").Select(u => new A {
Id = Int32.Parse(u.Element("Id").Value),
Bs = _ABs.Root.Elements("AB"). //?????
}).AsList();

Where _As, _ABs and _Bs are XDocuments loaded from the 3 XML files.

How can I fill Bs for each A?

There are probably many ways of doing that.

For one of them see below.

(note that I am not really using bxml/bdoc, because there are no need
in this example)

Arne

=====================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace E
{
public class A {
public Int32 Id { get; set; }
public IList<B> Bs { get; set; }
}
public class B {
public Int32 Id { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
string axml = @"<As>
<A>
<Id>1</Id>
</A>
<A>
<Id>2</Id>
</A>
</As>";
string bxml = @"<Bs>
<B>
<Id>1</Id>
</B>
<B>
<Id>2</Id>
</B>
<B>
<Id>3</Id>
</B>
</Bs>";
string abxml = @"<ABs>
<AB>
<AId>1</AId>
<BId>1</BId>
</AB>
<AB>
<AId>2</AId>
<BId>1</BId>
</AB>
<AB>
<AId>2</AId>
<BId>3</BId>
</AB>
</ABs>";
XDocument adoc = XDocument.Parse(axml);
XDocument bdoc = XDocument.Parse(bxml);
XDocument abdoc = XDocument.Parse(abxml);
List<A> alst = new List<A>();
foreach(int aid in from a in adoc.Root.Elements("A") select
int.Parse(a.Element("Id").Value))
{
alst.Add(new A { Id=aid, Bs=(from b in
abdoc.Root.Elements("AB") where int.Parse(b.Element("AId").Value)==aid
select new B { Id=int.Parse(b.Element("BId").Value) }).ToList() });
}
foreach(A aelm in alst)
{
Console.WriteLine(aelm.Id);
foreach(B belm in aelm.Bs)
{
Console.Write(" " + belm.Id);
}
Console.WriteLine();
}
Console.ReadKey();
}
}
}
 
shapper said:
I am trying to create a Many to Many relationship using XML files:
<As>
  <A>
    <Id>1</Id>
  </A>
  <A>
    <Id>2</Id>
  </A>
<As>
<ABs>
  <AB>
    <AId>1</AId>
    <BId>1</BId>
  </AB>
  <AB>
    <AId>2</AId>
    <BId>1</BId>
  </AB>
<ABs>
<Bs>
  <B>
    <Id>1</Id>
  </B>
  <B>
    <Id>2</Id>
  </B>
<Bs>
And my objects are simply:
public class A {
  public Int32 Id { get; set; }
  public IList<B> Bs { get; set; }
}
public class B {
  public Int32 Id { get; set; }
}
Basically, I need to create a List of objects A and for each fill the
Bs in each A.
      return _As.Root.Elements("A").Select(u => new A {
        Id = Int32.Parse(u.Element("Id").Value),
        Bs = _ABs.Root.Elements("AB"). //?????
      }).AsList();
Where _As, _ABs and _Bs are XDocuments loaded from the 3 XML files.
How can I fill Bs for each A?

There are probably many ways of doing that.

For one of them see below.

(note that I am not really using bxml/bdoc, because there are no need
in this example)

Arne

=====================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace E
{
     public class A {
         public Int32 Id { get; set; }
         public IList<B> Bs { get; set; }
     }
     public class B {
         public Int32 Id { get; set; }
     }
     public class Program
     {
         public static void Main(string[] args)
         {
             string axml = @"<As>
   <A>
     <Id>1</Id>
   </A>
   <A>
     <Id>2</Id>
   </A>
</As>";
             string bxml = @"<Bs>
   <B>
     <Id>1</Id>
   </B>
   <B>
     <Id>2</Id>
   </B>
   <B>
     <Id>3</Id>
   </B>
</Bs>";
             string abxml = @"<ABs>
   <AB>
     <AId>1</AId>
     <BId>1</BId>
   </AB>
   <AB>
     <AId>2</AId>
     <BId>1</BId>
   </AB>
   <AB>
     <AId>2</AId>
     <BId>3</BId>
   </AB>
</ABs>";
             XDocument adoc = XDocument.Parse(axml);
             XDocument bdoc = XDocument.Parse(bxml);
             XDocument abdoc = XDocument.Parse(abxml);
             List<A> alst = new List<A>();
             foreach(int aid in from a in adoc.Root.Elements("A") select
int.Parse(a.Element("Id").Value))
             {
                 alst.Add(new A { Id=aid, Bs=(from b in
abdoc.Root.Elements("AB") where int.Parse(b.Element("AId").Value)==aid
select new B { Id=int.Parse(b.Element("BId").Value) }).ToList() });
             }
             foreach(A aelm in alst)
             {
                 Console.WriteLine(aelm.Id);
                 foreach(B belm in aelm.Bs)
                 {
                     Console.Write("  " + belm.Id);
                 }
                 Console.WriteLine();
             }
             Console.ReadKey();
         }
     }

}

Isn't possible to use Linq to make this query. Just as I use when
using Linq to Sql. Just wondering.

Thanks,
Miguel
 
shapper said:
shapper said:
I am trying to create a Many to Many relationship using XML files:
<As>
<A>
<Id>1</Id>
</A>
<A>
<Id>2</Id>
</A>
<As>
<ABs>
<AB>
<AId>1</AId>
<BId>1</BId>
</AB>
<AB>
<AId>2</AId>
<BId>1</BId>
</AB>
<ABs>
<Bs>
<B>
<Id>1</Id>
</B>
<B>
<Id>2</Id>
</B>
<Bs>
And my objects are simply:
public class A {
public Int32 Id { get; set; }
public IList<B> Bs { get; set; }
}
public class B {
public Int32 Id { get; set; }
}
Basically, I need to create a List of objects A and for each fill the
Bs in each A.
return _As.Root.Elements("A").Select(u => new A {
Id = Int32.Parse(u.Element("Id").Value),
Bs = _ABs.Root.Elements("AB"). //?????
}).AsList();
Where _As, _ABs and _Bs are XDocuments loaded from the 3 XML files.
How can I fill Bs for each A?
There are probably many ways of doing that.

For one of them see below.

(note that I am not really using bxml/bdoc, because there are no need
in this example)

Arne

=====================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace E
{
public class A {
public Int32 Id { get; set; }
public IList<B> Bs { get; set; }
}
public class B {
public Int32 Id { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
string axml = @"<As>
<A>
<Id>1</Id>
</A>
<A>
<Id>2</Id>
</A>
</As>";
string bxml = @"<Bs>
<B>
<Id>1</Id>
</B>
<B>
<Id>2</Id>
</B>
<B>
<Id>3</Id>
</B>
</Bs>";
string abxml = @"<ABs>
<AB>
<AId>1</AId>
<BId>1</BId>
</AB>
<AB>
<AId>2</AId>
<BId>1</BId>
</AB>
<AB>
<AId>2</AId>
<BId>3</BId>
</AB>
</ABs>";
XDocument adoc = XDocument.Parse(axml);
XDocument bdoc = XDocument.Parse(bxml);
XDocument abdoc = XDocument.Parse(abxml);
List<A> alst = new List<A>();
foreach(int aid in from a in adoc.Root.Elements("A") select
int.Parse(a.Element("Id").Value))
{
alst.Add(new A { Id=aid, Bs=(from b in
abdoc.Root.Elements("AB") where int.Parse(b.Element("AId").Value)==aid
select new B { Id=int.Parse(b.Element("BId").Value) }).ToList() });
}
foreach(A aelm in alst)
{
Console.WriteLine(aelm.Id);
foreach(B belm in aelm.Bs)
{
Console.Write(" " + belm.Id);
}
Console.WriteLine();
}
Console.ReadKey();
}
}

}

Isn't possible to use Linq to make this query. Just as I use when
using Linq to Sql. Just wondering.

I am using LINQ.

I guess tht you are asking if the two LINQ's can be replaced
with a single LINQ.

Maybe it can, but at least I can not see how.

But why? Since the XDocument are in memory, then there
are not really any overhead of doing multiple LINQ's.

Arne
 
But why? Since the XDocument are in memory, then there
are not really any overhead of doing multiple LINQ's.

Yes,

I was trying to do it in a single Linq query:

IList<A> As = _As.Root.Elements("A").Select(a => new A {
Id = Int32.Parse(u.Element("Id").Value),
Bs = _ABs.Root.Elements("AB")
.Where(ab => ab.Element("Id") == a.Element("Id")).
.Select(ab => _Bs.Root.Elements("B")
.Select(b => new B {
Id = Int32.Parse(b.Element("Id").Value),
Name = b.Element("Id").Value)
}).Where(r => r.Id == ???

I am a little bit confused about your loops.
In my code, I think you are doing it, can't I get (in my Select
statement) the values of Bs which id is equal to ab.

Don't Linq convert into loops internally?
So this should be possible using a single Linq Query.
 
What about:

Dictionary<Int32, B> Bs = _Bs.Root.Elements("B").ToDictionary(b =>
(Int32)b.Element("Id"), b => new B { Id = (Int32)b.Element("Id") });

List<A> = _As.Root.Elements("A").Select(a => new A {
Id = Int32.Parse(a.Element("Id").Value),
Title = a.Element("Title").Value,
Bs = _ABs.Root.Elements("AB")
.Where(ab => ab.Element("Id").Value == a.Element
("Id").Value)
.Select(ab => Bs[Int32.Parse(ab.Element
("BId").Value)]).ToList()
}).ToList();

It compiles and is seems "cleaner" than using the loops.
 
shapper said:
Yes,

I was trying to do it in a single Linq query:
I am a little bit confused about your loops.
In my code, I think you are doing it, can't I get (in my Select
statement) the values of Bs which id is equal to ab.

Don't Linq convert into loops internally?
Yes.

So this should be possible using a single Linq Query.

Maybe.

Arne
 
shapper said:
What about:

Dictionary<Int32, B> Bs = _Bs.Root.Elements("B").ToDictionary(b =>
(Int32)b.Element("Id"), b => new B { Id = (Int32)b.Element("Id") });

List<A> = _As.Root.Elements("A").Select(a => new A {
Id = Int32.Parse(a.Element("Id").Value),
Title = a.Element("Title").Value,
Bs = _ABs.Root.Elements("AB")
.Where(ab => ab.Element("Id").Value == a.Element
("Id").Value)
.Select(ab => Bs[Int32.Parse(ab.Element
("BId").Value)]).ToList()
}).ToList();

It compiles and is seems "cleaner" than using the loops.

If you like it then fine.

I think it is very difficult to read and understand.

Loops are very simple constructs that are well known by
all developers. I can not see any reason to write complicated
code to avoid them.

Arne
 
Back
Top