generics - Linq to SQL: Many to Many support class -
i'd have support class many many relationship.
as see double generic class define in 1 or both of entity partial classes surrounding relationship.
getting allow access other table without having mention relationship table should easy. adding or removing collection trickier. ahve add row relationship table aswell , commit or remove based on done.
could done through function passed generic class?
does class exists , if not can viably done?
you can create imanytomanyset<tentity> interface can returned many many property , have manytomanyset<tsource, tcross, tdestination> implementation query insert , delete features.
the interface may this:
public interface imanytomanyset<tentity> : ienumerable<tentity> tentity : class { int count { get; } void add(tentity entity); bool remove(tentity entity); void addrange(ienumerable<tentity> collection); } and implementation might this:
public class manytomanyset<tsource, tcross, tdestination> : imanytomanyset<tdestination>, ienumerable<tdestination> tdestination : class tsource : class tcross : class { private tsource source; private entityset<tcross> crossset; private func<tcross, tdestination> destinationselector; private func<tsource, tdestination, tcross> crossfactory; public manytomanyset(tsource source, entityset<tcross> crossset, func<tcross, tdestination> destinationselector, func<tsource, tdestination, tcross> crossfactory) { this.source = source; this.crossset = crossset; this.destinationselector = destinationselector; this.crossfactory = crossfactory; } public int count { { return this.crossset.count; } } public void add(tdestination entity) { var newentity = this.crossfactory(this.source, entity); this.crossset.add(newentity); } public bool remove(tdestination entity) { var existingentity = ( c in this.crossset this.destinationselector(c) == entity select c) .singleordefault(); if (existingentity != null) { return this.crossset.remove(existingentity); } return false; } public void addrange(ienumerable<tdestination> collection) { foreach (var entity in collection) { this.add(entity); } } public ienumerator<tdestination> getenumerator() { return this.crossset.select(this.destinationselector) .getenumerator(); } ienumerator ienumerable.getenumerator() { return this.getenumerator(); } } you need supply couple of things in implementation:
- the
tsourceinstance, points @ entity defines property. - the
entityset<tcross>points list of entities define cross table. - a projection function allows convert
tcrosstdestination. - a factory function allows create new
tcrossbased ontsource,tdestination.
translating practical example (using product , order), give following property in order entity:
private imanytomanyset<product> products; public imanytomanyset<product> products { { if (this.products != null) { this.products = new manytomanyset<order, orderproduct, product>( this, this.orderproducts, op => op.product, (o, p) => new orderproduct { order = o, product = p }); } return this.products; } } and following property in product entity:
private imanytomanyset<order> orders; public imanytomanyset<order> orders { { if (this.orders == null) { this.orders = new manytomanyset<product, orderproduct, order>( this, this.orderproducts, op => op.order, (p, o) => new orderproduct { order = o, product = p }); } return this.orders; } } the imanytomanyset<t> interface in fact redundant, because can return manytomany<tsource, tcross, tdestination> directly. interface hides tsource , tcross type arguments, makes bit more readable user of property.
note implementation has same loading behavior linq sql's entityset<t>; when used, loads complete set of objects in memory. entityset<t> using where or first on collection, still loads complete collection database. need aware of that.
important difference linq sql understands entityset<t> properties within linq queries. having imanytomanyset<t> inside linq query fail miserably.
i hope helps.
Comments
Post a Comment