使用具体类型实现ICollection 以满足Entity Framework

所以,这是一个迟钝的问题,但让我看看我是否可以相对简单地说出来。 可以说我有以下界面:

public interface IFoo { ICollection Bars { get; set; } } 

然后我实施:

 public class Foo : IFoo { public virtual ICollection Bars { get; set; } } 

只有Entity Framework无法使用接口,所以它几乎完全忽略了这个导航属性。 为了让EF识别它,我需要将其更改为:

 public virtual ICollection Bars { get; set; } 

Bar应该是我对IBar实施。 只是,未能实现希望IBar不是Bar的界面。

现在,考虑一个稍微不同的场景,我刚刚得到一个基本的外键:

 public interface IFoo { IBar Bar { get; set; } } public class Foo : IFoo { public virtual IBar Bar { get; set; } } 

同样的问题,但在这里,我可以通过添加:

 public class Foo : IFoo { public virtual Bar Bar { get; set; } IBar IFoo.Bar { get { return Bar; } set { Bar = (Bar)value; } } } 

EF很高兴,因为它有一个具体的类型,界面很高兴,因为它有一个IBar的实现。 问题是我无法弄清楚如何在ICollection应用相同的逻辑,因为(ICollection)value引发了一个exception,说“不能将类型ICollection隐式转换为ICollection ”。

我应该如何正确地演出?

UPDATE

所以,我没有足够关注错误产生的位置。 它实际上抱怨get { return Bars; } get { return Bars; }位 通过将其更改为:我能够摆脱错误:

 public class Foo : IFoo { public virtual ICollection Bars { get; set; } ICollection IFoo.Bars { get { return (ICollection)Enumeration.Cast(Bars); } set { Bars = (ICollection)value; } } } 

这对我来说似乎有些小事,就像我只是掩饰错误并为自己制造一个小定时炸弹。 我很感激任何想法或替代解决方案。

为了让协方差/逆变工作,我将导航属性定义为我的接口中的枚举:

 public interface IFoo { IEnumerable Bars { get; } } public class Foo : IFoo { public virtual ICollection Bars { get; set; } IEnumerable IFoo.Bars { return this.Bars; } } 

对于基于接口类型构建的EF LINQ查询,这仍然足够了。

我使用像这样的通用接口适配器

 public class InterfaceCollectionAdapter : ICollection where TConcrete : TInterface { private Func> _gettor; private Action> _settor; private Func> _factory; private ICollection Wrapped { get { var value = _gettor(); if (value == null && _settor != null) { value = (_factory != null) ? _factory() : new List(); _settor(value); } return value; } } public InterfaceCollectionAdapter(Func> gettor, Action> settor = null, Func> factory = null) { _gettor = gettor; _settor = settor; _factory = factory; } public void Add(TInterface item) { Wrapped.Add((TConcrete)item); } public void Clear() { Wrapped.Clear(); } public bool Contains(TInterface item) { return Wrapped.Contains((TConcrete)item); } public void CopyTo(TInterface[] array, int arrayIndex) { var wrapped = Wrapped; foreach (var item in wrapped) { array[arrayIndex++] = (TInterface)item; } } public int Count { get { return Wrapped.Count; } } public bool IsReadOnly { get { return Wrapped.IsReadOnly; } } public bool Remove(TInterface item) { return Wrapped.Remove((TConcrete)item); } public IEnumerator GetEnumerator() { var wrapped = Wrapped; foreach (var item in wrapped) yield return item; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } 

然后在POCO中你就是这么做的

  public Foo() { public Foo() { _bars = new InterfaceCollectionAdapter(() => this.Bars, (value) => { this.Bars = value; }); } private InterfaceCollectionAdapter _bars; [NotMapped] ICollection IFoo.Bars { get { return _bars; } }