Ling to sql: Collection property mogelijk?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 15:24
Ik kan hier op google ed niet zoveel over vinden, vandaar dat ik mijn vraag hier stel. Ik heb twee tabellen die door middel van een koppeltabel met elkaar verbonden zijn (een veel-op-veel relatie dus)"

Articles
Id
Title
Description

Tags
Id
Text

ArticleTags
ArticleId
TagId

Als ik deze nu in Visual Studio vanuit de server explorer op een .dbml sleep, krijg ik drie classes:
Article, Tag en ArticleTag. Door de veel-op-veel relatie hebben zowel Article en Tag een ArticleTags EntitySet<ArticleTags> property. Het liefst zou ik eigenlijk willen hebben dat Article een Tags IEnumerbale<Tag> property heeft en Tag een IEnumerable<Article> property. Is dit standaard mogelijk met Linq to Sql of zal ik zelf het een en ander moeten gaan coden?

Roomba E5 te koop


Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Standaard past linq to sql dat niet aan en dat heeft vooral met de meta data te maken.

Echter alle entities zijn als partial gedefineerd dus je kunt wel zelf een Tags property eenvoudig toevoegen welke een wrapper voor ArticleTags.Tags is.

C#:
1
2
3
4
partial class Articles
{
    public IEnumerable<Tags> Tags { get { return ArticleTags.Tags; } }
}


De link met ArticleTags moet blijven omdat anders update/deletes/inserts lastig worden. Je hoeft in elk geval geen eigen linq queries te schrijven.

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • mOrPhie
  • Registratie: September 2000
  • Laatst online: 11:35

mOrPhie

❤️❤️❤️❤️🤍

Het is niet standaard mogelijk. LINQ to SQL ondersteunt geen Many-to-Many relaties. LINQ to Entities straks wel, maar dat moet dus nog uit komen.

Ik heb het opgelost door een property toe te voegen aan m'n partial class. In jouw geval bijvoorbeeld in "Article" dit toevoegen:

C#:
1
2
3
4
5
6
7
8
9
10
public IEnumerable<Tag> Tags
{
    get
    {
        IEnumerable<Tag> tags = 
             from t in this.ArticleTags
             select t.Tag;
        return tags;
    }
}


Je verliest dan wel de queryable interface, waardoor LINQ op deze collectie niet voor SQL zal zorgen, maar in memory wordt gequeried. Je kunt dat wel voor elkaar krijgen, maar dat is wat lastiger. Daar heb ik een blogpost over gelezen. Mocht je dat willen, kan ik het wel even voor je opzoeken. :)
Niemand_Anders schreef op vrijdag 20 juni 2008 @ 09:59:
Echter alle entities zijn als partial gedefineerd dus je kunt wel zelf een Tags property eenvoudig toevoegen welke een wrapper voor ArticleTags.Tags is.
Dat gaat niet, aangezien de collectie (EntitySet) "ArticleTags" geen "Tags" property heeft. Je moet dus wel een stukje LINQ doen, zoals ik hierboven laat zien. :)

[ Voor 45% gewijzigd door mOrPhie op 20-06-2008 10:14 ]

Een experimentele community-site: https://technobabblenerdtalk.nl/. DM voor invite code.


Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 15:24
Ah, jammer, dan maar zo. Het is niet veel code maar het had leuk geweest. Dat ArticleTags geen Tags proeprty heeft wilde ik al opmerken. LINQ to Entities ga ik ook in de gaten houden, klinkt ook goed :)

Roomba E5 te koop


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 17:34
mOrPhie schreef op vrijdag 20 juni 2008 @ 10:07:
Het is niet standaard mogelijk. LINQ to SQL ondersteunt geen Many-to-Many relaties. LINQ to Entities straks wel, maar dat moet dus nog uit komen.
Volgens mij is dat in LINQ to entities ook gerealiseerd met EntitySet ?
Een alternatief is natuurlijk NHibernate.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • mOrPhie
  • Registratie: September 2000
  • Laatst online: 11:35

mOrPhie

❤️❤️❤️❤️🤍

Dat zou ik wellicht moeten uitzoeken. Wat ik wel weet is dat LINQ to SQL standaard voor elke tabel een class genereert, waar LINQ to Entities koppeltabellen herkent en daarvoor dan default al direct access tot de lijsten geeft, zonder een class te genereren voor die koppeltabel. In deze situatie zou je dus al direct een Article.Tags en een Tag.Articles property krijgen. Het querien van deze properties zorgt, mits je maar 1 keer enumereert, voor 1 sql-query en bij mijn weten wordt het hele many-to-many verhaal dus in de IQueryable opgelost.

[ Voor 5% gewijzigd door mOrPhie op 20-06-2008 10:47 ]

Een experimentele community-site: https://technobabblenerdtalk.nl/. DM voor invite code.


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
mOrPhie schreef op vrijdag 20 juni 2008 @ 10:32:
Dat zou ik wellicht moeten uitzoeken. Wat ik wel weet is dat LINQ to SQL standaard voor elke tabel een class genereert, waar LINQ to Entities koppeltabellen herkent en daarvoor dan default al direct access tot de lijsten geeft, zonder een class te genereren voor die koppeltabel. In deze situatie zou je dus al direct een Article.Tags en een Tag.Articles property krijgen. Het querien van deze properties zorgt, mits je maar 1 keer enumereert, voor 1 sql-query en bij mijn weten wordt het hele many-to-many verhaal dus in de IQueryable opgelost.
...maar zo'n hidden intermediate entity is niet te prefereren:
DepartmentEmployee
- DepartmentID *
- EmployeeID *
- Startdate

Nu kan hij niet meer hidden zijn. Wanneer je startdate er later bij prakt, dan komt deze entity ineens tevoorschijn en is je code zeer waarschijnlijk niet meer correct.

m:n relaties zijn ook per definitie readonly omdat het een view is op 2 aparte relaties. (2x m:1), en de readonly komt door het bovenstaande. Het is doordat het readonly is dat veel o/r mappers er moeite hebben met m:n relaties.

Let bij die extra property wel op dat je per Article dus een query krijgt voor de tags, wat wellicht trager is. Maar goed, Linq to Sql heeft uberhaupt geen goede hierarchische queries dus qua performance zakt het toch al in bij enumerations over entities waarbij je dan een gerelateerde set opvraagt.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Acties:
  • 0 Henk 'm!

  • mOrPhie
  • Registratie: September 2000
  • Laatst online: 11:35

mOrPhie

❤️❤️❤️❤️🤍

EfBe schreef op vrijdag 20 juni 2008 @ 13:46:
[...]
Let bij die extra property wel op dat je per Article dus een query krijgt voor de tags, wat wellicht trager is.
Ja, zoals ik ook al aangaf verlies je de IQueryable interface en behandeld LINQ de rest dus als een enumerable. Daar moet je behoed op zijn. Dat is trouwens niet alleen zo bij LINQ to SQL, dat is bij alles wat IQueryable implementeerd. Als je wat je terug krijgt als IEnumerable representeert, gaat LINQ to Objects z'n werk doen.
Maar goed, Linq to Sql heeft uberhaupt geen goede hierarchische queries dus qua performance zakt het toch al in bij enumerations over entities waarbij je dan een gerelateerde set opvraagt.
Hoe bedoel je dat? Dat de queries die dynamisch worden gemaakt niet optimaal zijn bij gerelateerde data?

[ Voor 24% gewijzigd door mOrPhie op 20-06-2008 16:20 ]

Een experimentele community-site: https://technobabblenerdtalk.nl/. DM voor invite code.


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
mOrPhie schreef op vrijdag 20 juni 2008 @ 16:20:
[...]
Ja, zoals ik ook al aangaf verlies je de IQueryable interface en behandeld LINQ de rest dus als een enumerable. Daar moet je behoed op zijn. Dat is trouwens niet alleen zo bij LINQ to SQL, dat is bij alles wat IQueryable implementeerd. Als je wat je terug krijgt als IEnumerable representeert, gaat LINQ to Objects z'n werk doen.
Nou, de iterator gaat iedere Tags property uitlezen, en dus voor ieder article een Tags query runnen, maar dat gaf jij idd ook aan. Dus voor 100 articles in een list en je gaat die tags uitlezen levert dat dus 100 extra queries op.
[...]
Hoe bedoel je dat? Dat de queries die dynamisch worden gemaakt niet optimaal zijn bij gerelateerde data?
Ja, Linq to Sql heeft erbarmelijke hierarchische fetch code.

Lees maar eens in: Customer - Order - OrderDetails. Dat kan in 3 queries. Maar niet in de wereld van Linq to Sql. :)

Of:
C#:
1
2
3
4
5
6
7
var q = from c in ctx.Customers
          where c.Country=="USA"
         select new {
                   c.CustomerId,
                   Orders = (from o in c.Orders
                                  select new { o.OrderId, o.OrderDate})
          };


Dat gaat ie in 1+#customers doen. Tja... :)

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Acties:
  • 0 Henk 'm!

  • mOrPhie
  • Registratie: September 2000
  • Laatst online: 11:35

mOrPhie

❤️❤️❤️❤️🤍

Jups. Aanvullend hierop (hoef ik EfBe waarschijnlijk niet te vertellen, maar voor de rest in dit topic dan. ;) ): Entity Framework doet "deferred loading" van gerelateerde data. Soort van Lazy Loading, maar dan kun je het moment van laden zelf kiezen. Niet per se als je de gerelateerde data gebruikt. Wat de gedachte daarachter is geweest weet ik ook niet, maar het is in elk geval goed om te weten dat Entity Framework hier iets verstandiger mee om gaat.

Een experimentele community-site: https://technobabblenerdtalk.nl/. DM voor invite code.

Pagina: 1