Linq Many to Many relationship and XML

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
 
A

Arne Vajhøj

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();
}
}
}
 
S

shapper

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
 
A

Arne Vajhøj

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
 
S

shapper

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.
 
S

shapper

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.
 
A

Arne Vajhøj

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
 
A

Arne Vajhøj

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top