I have the following entities:
public interface IMyEntity
{
[Key]
int Id { get; set; }
IMyDetail MyDetail { get; set; }
ICollection
I had this issue too on some on my models and not others and tried using the accepted answer. Then I dug a bit deeper as to what was different on the models that worked.
Fix was to change from using ICollection to use IEnumerable instead and the issues went away, so far.
This removed the need to use the below code in accepted answer:
public interface IParent<out TChild>
where TChild : IChild
{
ICollection<TChild> Children { get; set; }
and it became
public interface IParent
{
IEnumerable<IChild> Children { get; set; }
which is much simpler.
An imperfect solution is to just merge these interfaces you want to persist into base classes and break down the underlying objects with subclasses. EF does support this, and if you go with Table Per Hierarchy (the default), you can sort all of the underlying subclassed objects by a shared property using a regular LINQ query from EF instead of having to get crafty and do things like write raw SQL or get multiple lists into memory and sort the union without the help of the DB, like you would with Cel's solution of interfaces and adapters.
You could also take the child/parent types of interfaces as generics, so that when the implementer uses concrete classes in the Db they can mostly use your interfaces, but tell EF to use concrete classes:
public interface IParent<out TChild>
where TChild : IChild
{
ICollection<TChild> Children { get; set; }
Someone could create their Db classes like:
public class Parent : IParent<Child>
. . .
But still use them like:
IParent<IChild> parents = db.Parents.Include(p => p.Children).ToArray();
Because the generic is marked out
, the generic is covariant and therefore can take anything that meets the generic's restrictions, including the above cast up the type tree to the IChild interface.
That said, if you really want to persist interfaces, the right answer is probably to use NHibernate: How to map an interface in nhibernate?
And some coders recommend you keep interfaces on entities in any ORM limited to a few shared properties, or risk misuse: Programming to interfaces while mapping with Fluent NHibernate
A workaround is to create a special implementation for each interface you want to use with Entity Framework, utilizing the adapter pattern:
// Entity Framework will recognize this because it is a concrete type
public class SecondLevelDomainRep: ISecondLevelDomain
{
private readonly ISecondLevelDomain _adaptee;
// For persisting into database
public SecondLevelDomainRep(ISecondLevelDomain adaptee)
{
_adaptee = adaptee;
}
// For retrieving data out of database
public SecondLevelDomainRep()
{
// Mapping to desired implementation
_adaptee = new SecondLevelDomain();
}
public ISecondLevelDomain Adaptee
{
get { return _adaptee; }
}
public string Id
{
get { return _adaptee.Id; }
set { _adaptee.Id = value; }
}
// ... whatever other members the interface defines
}
// Repositor is your DbContext
public void SubmitDomain(ISecondLevelDomain secondLevelDomain)
{
Repositor.SecondLevelDomainReps.Add(new SecondLevelDomainRep(secondLevelDomain));
Repositor.SaveChanges();
}
public IList<ISecondLevelDomain> RetrieveDomains()
{
return Repositor.SecondLevelDomainReps.Select(i => i.Adaptee).ToList();
}
For more complex interfaces/classes, you may get InvalidOperationException - see Conflicting changes with code first foreign key in Entity Framework for an implementation that works with such object hierarchies
After several sleepless nights I believe I have found a solution to this problem. I have tested this approach (a little) and it seems to work but it probably needs some more eyeballs to tear it apart and explain why this approach might break. I used FluentAPI to set up my database attributes instead of decorating the entity class properties. I've removed the virtual attribute from the entity class members (i prefer to use explicit includes instead of falling back on lazy loading for child entities). I've also renamed the example classes and properties a bit so that it is clearer to me. I'm assuming you are trying to express a one-to-many relationship between an entity and its details. You are trying to implement interfaces for your entities in the repository tier so that upper tiers are agnostic to the entity classes. Higher tiers are only aware of the interfaces not the entities themselves...
public interface IMyEntity
{
int EntityId { get; set; }
//children
ICollection<IMyDetailEntity> Details { get; set; }
}
public interface IMyDetailEntity
{
int DetailEntityId { get; set; }
int EntityId { get; set; }
int IntValue { get; set; }
//parent
IEntity Entity { get; set; }
}
public class MyEntity : IMyEntity
{
public int EntityId { get; set; }
private ICollection<IMyDetailEntity> _Details;
public ICollection<MyDetailEntity> Details {
get
{
if (_Details == null)
{
return null;
}
return _Details.Select(x => (MyDetailEntity) x).ToList();
}
set
{
_Details = value.Select(x => (IMyDetailEntity) x).ToList();
}
}
ICollection<IMyDetailEntity> IMyEntity.Details
{
get
{
return _Details;
}
set
{
_Details = value;
}
}
}
public class MyDetailEntity : IMyDetailEntity
{
public int DetailEntityId { get; set; }
public int EntityId { get; set; }
public int IntValue { get; set; }
private IMyEntity _Entity;
public MyEntity Entity
{
get
{
return (Entity)_Entity;
}
set
{
_Entity = (Entity)value;
}
}
IEntity IMyDetailEntity.Entity
{
get
{
return _Entity;
}
set
{
_Entity = value;
}
}
}
I've had the same problem and found a solution just like Nathan, but you can even take it one step further and have the properties named the same (here Extensions
and IAddress.Extensions
), by explicitly defining the interface:
public interface IAddress
{
string Address { get; set; }
IEnumerable<IAddressExtension> Extensions { get; set; }
}
public interface IAddressExtension
{
string Key { get; set; }
string Value { set; }
}
[Table("AddressExtensions")]
public class AddressExtension : IAddressExtension
{
[Key]
public string Id { get; set; }
public string Key { get; set; }
public string Value { get; set; }
}
[Table("Addresses")]
public class Address : IAddress
{
[Key]
public string Id { get; set; }
public string Address { get; set; }
public IEnumerable<AddressExtension> Extensions { get; set; }
[NotMapped]
IEnumerable<IAddressExtension> IAddress.Extensions
{
get { return Extensions; }
set { Extensions = value as IEnumerable<AddressExtension>; }
}
}
Code First ignores the interface-property and uses the concrete class, while you can still access this class as an interface of IAddress
.
I had a simliar case and I solved it this way:
public class Order : IOrder
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<OrderItem> Items {get; set;} = new List<OrderItem>();
IEnumerable<IOrderItem> IOrder.Items
{
get { return Items; }
set { Items = value as List<OrderItem>; }
}
}
public class OrderItem: IOrderItem
{
public string Name {get; set;}
public decimal Price {get; set;}
}