问题
I have a many-to-many mapping/pivot table I had to expose as an Entity in order to model a relationship similar to the following (as per this question Model Entity Framework many-many plus shared relation):
Now, I would like to emulate the EF collection Enumerate/Add/Remove functionality that is present on the navigation property of a 'stock' Entity Framework many-to-many relationship. How would I do that?
I'm hoping for something that I can still query without blowing my data performance. Obviously just implementing the following to bridge the pivot table doesn't accomplish this goal, and also doesn't follow the EF conventions for managing the collection:
public partial class Composition {
public IEnumerable<Anthology> Anthologies {
get {
return CompositionAnthologies.Select(e => e.Anthology);
}
}
public void AddAnthology(Anthology anthology)
{
CompositionAnthologies.Add(new CompositionAnthology() {
Anthology = anthology,
Composer = Composer
});
}
}
Can you point me at an example or recommend a starting point? (Note I'm using model-first currently, but would switch to code-first for a solution, since model-first seems to be fast becoming a second-class citizen.)
EDIT: Here's further info on the relationship and constraints.
The many-to-many relationship has a junction table ("CompositionAnthologies") including a binding ComposerId column, with necessary manually-created FK relations to enforce Composition.Composer == Anthology.Composer for all Anthology.Compositions (and Composition.Anthologies). Here is the relation as held by the junction table:
i.e.There must be no Compositions related to Anthologies, but having differing Composers.
回答1:
Here's my current solution. Still open to suggestions, as this obscures IQueryable, which has performance ramifications. It also doesn't have Context, so cannot delete junctions (notice the NotImplemented exceptions). The latter issue is not terribly important for me, because my data has a deleted flag that I use anyway.
Here's one side of the relation. They are symmetric.
public partial class Composition {
public ICollection<Anthology> Anthologies {
get {
return new JunctionedAnthologies(this);
}
}
}
public class JunctionedAnthologies : ICollection<Anthology> {
private readonly Composition _parent;
public JunctionedAnthologies(Composition parent)
{
_parent = parent;
}
public void Add(Anthology item) {
if (item.Composer == null) {
if (_parent.Composer == null) throw new InvalidOperationException("The parent or child Composer must be set to form this association");
item.Composer = _parent.Composer;
}
else if (_parent.Composer == null) {
_parent.Composer = item.Composer;
}
else if (item.Composer != _parent.Composer) {
throw new InvalidOperationException("The parent and child must not have a differing Composer assigned");
}
junction.Add(new CompositionAnthology() {
Anthology = item,
Composer = item.Composer
});
}
public void Clear() {
throw new NotImplementedException();
}
public bool Contains(Anthology item) {
return junction.Any(j => j.Anthology == item);
}
public void CopyTo(Anthology[] array, int arrayIndex) {
throw new NotImplementedException();
}
public int Count {
get { return junction.Count; }
}
public bool IsReadOnly {
get { return false; }
}
public bool Remove(Anthology item) {
throw new NotImplementedException();
}
public IEnumerator<Anthology> GetEnumerator() {
return junction.Select(e => e.Anthology).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
private ICollection<CompositionAnthology> junction {
get {
return _parent.CompositionAnthologies;
}
}
}
来源:https://stackoverflow.com/questions/16312984/custom-entity-framework-many-to-many-navigation-property